java 虚拟机内存模型主要有三大部分
- 运行数据区
- 执行引擎
- 本地方法接口
我们平常需要了解和关注的主要是有关运行数据区的详细信息
运行数据区主要有五大部分
- 栈(虚拟机栈是JAVA方法执行的内存模型,包括多个栈帧,每个栈帧包括局部变量表,操作栈,动态连接,返回地址等)
- 堆(存储对象)
- 程序计数器
- 本地方法栈
- 方法区(元数据区 1.8?)
https://zhuanlan.zhihu.com/p/161994662
清楚了内存模型,就可以开始了解GC
怎么定义垃圾
- 引用计数法
在堆中的对象会有一个引用标志位,当改对象实例被引用一次,改标志位+1 ,当引用释放(主动或被动),该引用 -1 。
当值为0时,则视为改对象实例无人引用,可作为垃圾
缺点:存在循环引用的情况会导致内存泄漏。 - 可达性算法
从GC root开始进行图状的遍历,从GC root 开始,通过引用可以到达的对象实例是活跃对象实例,其余的则视为垃圾
可作为GC root的变量(对象):
虚拟机栈中局部变量表中变量(引用的对象)
方法区(元空间)中的常量(引用的对象)
方法区(元空间)中类静态变量(引用的对象)
本地方法栈中JNI引用的对象
https://segmentfault.com/a/1190000038405609
如何清理垃圾
- 标记-清理
直接标了直接请
缺点:内存空间碎片化 - 标记-清理
标完之后将活着的整理到一起,清理剩余空间
缺点:资源消耗大,时间慢
3.复制-清理
将活着的一起复制到另一个内存区域
清理之前的
组合拳(第一弹):
eden区
对象产生的地方当eden区满后 ,则会触发minor GC
survival from 区
当minorGC触发时,会通过可达性算法找出eden区以及当前survival 区的存活对象
将其全部移动到survival 0区
当survival 0 区满时,则会在进行一次minorGC , 将当前的移动到 survival 1区
每进行一次移动,对象的年龄就会增加1
默认15 次之后, 会将该对象移动到老年代
可以通过参数 -XX:MaxTenuringThreshold (阈值)来设置
老年代:
采用标记-清理算法
如果老年代满,则会出发一次full GC
fullGC 包含 minor GC (年轻代)和mayjor GC(老年代)
STW
stop the word
进行垃圾回收时,jvm需要所有进程达到安全点后暂停所有用户线程,称为 stw
安全点:
方法调用时,循环跳转时,异常跳转时
组合拳第二弹:
serial 垃圾收集器(复制算法) -XX: UseSerialGC
单线程收集器,年轻代收集器,收集时造成STW,暂停所有用户线程
client jvm 默认垃圾收集器
parnew 垃圾收集器(复制算法) -XX: UseParNewlGC
并行垃圾处理器 , 年轻代收集器,收集时造成STW,暂停所有用户线程
parallel scavange垃圾收集器(复制算法) -XX: UseParallelGC
并行垃圾处理器 ,年轻收集器,更注重系统吞吐量(用户代码运行时间/用户+垃圾收集器运行时间)
多核下有优势,server jvm 默认垃圾收集器,适合计算量高的后端
可以通过 -XX : UseAdaptiveSizePolicy 来使其采用自适应优化