概述

无论哪种GC都会对内存进行分块,将不同的对象放入不同的区块之中。

运行时数据区

程序计数器、堆、栈、方法区、本地方法区、运行时常量区。

堆(Heap)

Young Generation(新生代)
Young为Eden和Survivor,而Survivor由FromSpace和ToSpace组成。
Young中的98%的对象都是朝生夕死,所以将内存分为一块较大的Eden和两块较小的Survivor1(FromSpace)、Survivor2(FromSpace)
Eden、Servivor1、Servivor2默认分配比例8:1:1
Old Generation(老生代)
默认的新生代(Young generation)、老年代(Old generation)所占空间比例为 1 : 2 。
Permanent Generation(永久代)

GC方式

从Young中移走为MinorGC。
对象没有变得不可达,并且从新生代周期中存活了下来,会被拷贝到Old。
其区域分配的空间要比新生代多。也正由于其相对大的空间,发生在老年代的GC次数要比新生代少得多。对象从Old中消失的过程,为MajorGC或者FullGC
Young中使用Copying复制算法
Old中使用Mark-Compact标记整理算法

GC执行顺序

1、绝大多数刚刚被创建的对象会存放在伊甸园空间(Eden)。
2、在伊甸园空间执行第一次GC(Minor GC)之后,存活的对象被移动到其中一个幸存者空间(Survivor)。
3、此后,每次伊甸园空间执行GC后,存活的对象会被堆积在同一个幸存者空间
4、当一个幸存者空间饱和,还在存活的对象会被移动到另一个幸存者空间。然后会清空已经饱和的哪个幸存者空间。
5、在以上步骤中重复N次(N = MaxTenuringThreshold(年龄阀值设定,默认15))依然存活的对象,就会被移动到老年代。
从上面的步骤可以发现,两个幸存者空间,必须有一个是保持空的。如果两个两个幸存者空间都有数据,或两个空间都是空的,那一定是你的系统出现了某种错误。
我们需要重点记住的是,对象在刚刚被创建之后,是保存在伊甸园空间的(Eden)。那些长期存活的对象会经由幸存者空间(Survivor)转存到老年代空间(Old generation)。
也有例外出现,对于一些比较大的对象(需要分配一块比较大的连续内存空间)则直接进入到老年代。一般在Survivor 空间不足的情况下发生。
**

判断回收条件

· 对象没有引用
· 作用域发生未捕获异常
· 程序在作用域正常执行完毕
· 程序执行了System.exit()
· 程序发生意外终止(被杀线程等)

Permanent持久带GC为MajorGC发生条件苛刻:
1、类的所有实例被回收
2、加载该类的ClassLoader 被回收
3、Class 对象无法通过任何途径访问(包括反射)

GC Root

Remembered Set

“记忆集”,

注意

GC与非GC时间耗时超过了GCTimeRatio的限制引发OOM。

有些时候我们可以将相关的对象设置成null 来试图显示的清除缓存,但是并不是设置为null 就会一定被标记为可回收,有可能会发生逃逸。

将对象设置成null 至少没有什么坏处,但是使用System.gc() 便不可取了,使用System.gc() 时候并不是马上执行GC操作,而是会等待一段时间,甚至不执行,而且System.gc() 如果被执行,会触发Full GC ,这非常影响性能。

参考资料

图文讲解
https://blog.csdn.net/future234/article/details/80677140