1、java内存区域:
堆,主要存放实例对象,逃逸分析的对象不在堆里,字符串常量池,静态变量
Java 虚拟机栈,方法运行的入栈出栈
线程本地方法栈,本地方法的入栈出栈,实际上两个栈是合并的
程序计数器,记录线程执行的字节码指令地址,native方法未定义
元空间,类的元数据,字节码,运行时常量池,
2、不会内存溢出的区域:程序计数器,占一小块内存,控制字节码执行,线程切换保存运行上下文
3、堆溢出的原因:
- 内存泄漏,
- 短时间大量对象分配内存
4、字符串常量池:避免重复创建,移到堆里,因为永久代回收效率低,而字符串经常需要被回收
5、gc方法:引用计数循环依赖
gcroot:两种栈中对象,线程,方法区的静态变量和常量,锁中对象,jni引用
6、引用类型:
- 强,引用可达不可回收
- 弱,gc回收
- 虚,回收时进队列
- 软,内存不足被回收
7、算法
标记-清除:直接扔,有碎片。
复制:搬走有用的,清空另一半,无碎片但费空间。
标记-整理:把有用的挤到一边,再清空另一边,无碎片但费力气。
8、回收器
g1:初始标记(STW)并开启写屏障 → 并发标记整个对象图 → 最终标记(STW)处理写屏障记录 → 并发筛选出垃圾最多的 Region 组成回收集合 → STW 复制存活对象到空闲 Region,更新引用,回收原 Region。(更新引用的策略,卡表)
cms:"初始标记(STW)→ 并发标记整个对象图(同时写屏障记录变化)→ 最终标记(STW,处理写屏障记录)→ 并发清除, 清除期间写屏障仍然工作,处理新引用变化,垃圾变活需要跳过,活变垃圾下次回收,新对象默认存活**"**
zgc:
9、类加载原理
10、双亲委派:从自定义加载器向上委派到启动类加载器,启动类加载器先尝试加载;它加载不了,再逐层向下交给扩展、应用、自定义加载器。最终,JDK 核心类由启动类加载器加载,扩展类由扩展类加载器加载,应用类由应用类加载器加载,自定义类由自定义加载器加载。
打破:重写
11、问题排查流程:
想不触发 Full GC 看存活的大对象 :用 Arthas vmtool --action heapAnalyze,它通过遍历 GC Roots 来统计,结果更接近真实内存占用,且能直接给出引用链。
vmtool --action heapAnalyze --classNum 10 --objectNum 3
referenceAnalyze 可以分析指定类的实例,输出其中占用最大的若干对象,并回溯它们的引用链直至 GC Root,直接回答"这个对象为什么没被回收"
vmtool --action referenceAnalyze --className com.example.YourLargeObject --objectNum 5 --backtraceNum 3