1.触发垃圾回收的条件
- 新生代 Eden区域满了,触发young gc (ygc)
- 老年代区域满了,触发full gc (fgc)
- MetaSpace空间不足,触发full gc (fgc)
- 通过ygc后进入老年代的平均大小大于老年代的可用内存,触发full gc(fgc).
- 程序中主动调用的System.gc()强制执行gc,是full gc,但是不必然执行。
2.垃圾回收流程
- 当Eden满后,会触发young gc, 把有引用存活的对象复制到S0区域,回收清空Eden区域。
- 当Eden再次满后,触发young gc, 把Eden和S0区域的存活对象复制到另一个S1区域,收回清空Eden和S0区域。
3.对象进入老年代的场景
对象首次创建会被放置在新生代的eden区
对象进入老年代主要有下面三种方式:
- 大对象
- 比如很长的字符串、很大的数组等
- 可通过参数-XX:PretenureSizeThreshold=3145728设置,超过这个参数设置的值就直接进入老年代
- 长期存活的对象
- 对象头中(Header)包含了 GC 分代年 龄标记信息。如果对象在 eden 区出生,那么它的 GC 分代年龄会初始值为 1
- 每熬过一次 Minor GC 而不被回收,这个值就会增 加 1 岁。当它的年龄到达一定的数值时,就会晋升到老年代中
- 可以通过参数 -XX:MaxTenuringThreshold 设置年龄阀值(默认是 15 岁)
- 动态对象年龄判定
- 当 Survivor 空间中相同年龄所有对象的大小总和大于 Survivor 空间的一半。
- 年龄大于或等于该年龄的对象就可以直接进入老年代,而不需要达到默认的分代年龄。
4.对象存活判定
由于程序计数器、栈、本地方法栈都是线程独享,其占用的内存是随线程结束而回收。而Java堆和方法区则不同,线程共享,是GC的所关注的部分。
引用计数算法
给对象添加一个引用计数器,当有一个地方引用对象是计数器加1,当引用失效是计数器减1,当该对象的计数器为0时表示可以回收。
可达性分析算法
从GC Roots对象作为起点向下搜索,当一个对象不在GC Roots的引用链路中时,该对象可以回收。
GC Roots对象包含:方法区静态属性引用的对象、栈中引用的对象、本地方法栈中Native方法引用的对象、常量引用的对象。
从GC Roots开始,把所有可以搜索得到的对象标记为存活对象,固定可作为GC Roots的对象包括以下几种:·
v 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。·
v 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。·在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
v 在本地方法栈中Native方法引用的对象。
v Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
v 所有被同步锁(synchronized关键字)持有的对象。