目录
4、Generational Collection(分代收集)算法
3、Minor GC、Major GC和Full GC之间的区别?
一、JVM内存模型
二、为什么要进行垃圾回收?
随着程序的运行,内存中存在的实例对象,变量等信息占据的内存会越来越多,如果不及时进行垃圾回收,必然会带来性能下降问题,并且可能会由于内存不足造成一些不必要的异常。
三、哪些区域需要进行垃圾回收?
由于在jvm内存中,堆 和 方法区 属于线程共享的,需要通过垃圾回收机制来管理内存。
堆:是垃圾回收的主要场地,回收前需要判断哪些对象可以回收,哪些不可以回收。
因而就需要判断对象是否存活的算法:
- 引用计数算法:存在引用关系,计数器+1,释放引用关系,计数器 -1,计数器为0的对象就可以被回收
- 可达性分析算法:从一个GC Root出发,发现所有具有引用关系的节点,不存在引用关系的节点就可以被回收
四、GC Root的选取:
- 指向虚拟机栈中引用 的 对象
- 指向本地方法栈引用 的 对象
- 指向方法区中常量引用 的 对象
- 指向方法区中静态属性引用 的 对象
/** 指向静态属性引用 的 对象singleton **/ private static Singleton singleton;
相关问题:单例模式是怎么保证不会垃圾回收机制回收的?
根据GC Root的选取条件:
单例模式创建的对象被自己类中的静态变量引用,可以作为GC Root,所以不会被垃圾回收机制回收掉
五、常用的垃圾回收算法:
在确认了哪些对象需要被回收以后,就需要选择高效的方式进行垃圾回收。下面介绍几种常见的垃圾回收算法:
1、Mark-Sweep(标记-清除)算法
属于最基础的垃圾回收方式,垃圾回收分为两个阶段:标记阶段和回收阶段,及标记出来需要被清除的对象,然后释放该对象所占用的空间。
如图中所示,该回收方式会造成大量的内存碎片,因而会导致在之后续过程中如果需要申请比较大的内存空间会申请不到。在无法正常申请到内存空间的时候就会出发新的一次GC。
2、Copying(复制)算法
为了解决标记回收算法造成的内存碎片问题,提出提出了复制算法。具体过程为:它可以将内存空间按照容量平均分成两块,每次只使用一块,当这一块内存使用完了,就将这块内存中存活的对象都复制到另一块内存上去,让后把第一块内存一次性释放。从而减少了内存碎片的产生。
这种回收方式,虽然实现简单,运行效率高并且可以减少内存碎片的产生。但是该算法的内存使用率低,因为只有一半内存是可使用的。并且如果存活的对象过多,Copying算法的效率就会明显降低。
3、Mark-Compact(标记-整理)算法(压缩法)
为了解决Copying算法的痛点,合理利用内存空间,提出了标记—整理算法。第一步先对需要回收对象进行标记,然后不直接将对象回收掉,而是将存活的对象统一向一端移动,然后释放存活对象边界以外的所有内存空间。
但是每次也需要去标记所有的对象。
4、Generational Collection(分代收集)算法
分代回收是目前jvm采用最多的垃圾回收算法,他的核心思想是根据对象的生命周期将内存化为成多个区域,并根据不同区域对象生命周期的特点采用不用的垃圾回收算法。堆内存一般会划分为新生代和老年代。
新生代:每次回收都会有大量的对象会被回收掉,一般采用Copying算法进行回收,因为它需要回收的对象比较多,所以不会复制太多次的。但实际的内存分配并不是按照一半一半的区分的,而是会根据8:1:1的比例分成三块区域。
老年代:每次回收只会有少了的对象会被回收掉,一般采用的是标记-压缩算法进行回收。
六、分代回收的过程:
1、标记可回收对象
通过 可达性算法,将与GC Root不存在引用关系的对象,进行第一次标记;
被第一次标记的对象,进行再一次筛选,判断该对象是否需要执行finalize()方法(Object类公共方法),在finalize()方法中未重新建立连接的对象,进行第二次标记,就可以被回收了;
2、进行对象回收
- 堆:划分为 新生代(大量的对象需要回收)和 老年代(少量对象需要回收)
- 方法区:永久代(元空间,Java8以后用元空间代替了永久代)
过程:
- 新生代:分为三部分,按照8:1:1的比例分为eden区和两个Survivor区;垃圾回收时,先将eden区存活的对象放在survivor0中,清空eden区。当survivor0区放满后,对eden区和survivor0去进行回收,然后将两区域存活的所有对象放到survivor1区中,之后清空eden区和survivor0区,然后交换survivor0和survivor1区。当survivor1区不足以存放 survivor0和eden区中的对象的时候,这些对象会直接被放入老年代。
- 老年代:老年代满了以后会触发full GC。
- 永久代(元空间):永久代写满以后会触发full GC。
3、Minor GC、Major GC和Full GC之间的区别?
- Minor GC:指的是新生代GC,即新生代的垃圾回收操作。当在新生代申请内存空间失败以后,就会触发Minor GC。因为新生代的对象生命周期都很短,所以Minor GC的频率很高。虽然Minor GC会触发“stop-the-world”(暂停其他所有线程,造成系统全局停顿),但是它的回收速度很快。
- Major GC:用于老年代的回收,一次Major GC通常会至少出现一次Minor GC;
- Full GC:用于新生代,老年代,元空间的垃圾回收。
4、触发 full GC(对整个堆进行回收)的时机:
- 老年代写满
- 永久代写满
- system.gc()
- 上一次GC 后堆各个区域分配策略动态变化
七、JDK8之后JVM内存——Metaspace元空间
在Java8 以后,使用元空间来替换了永久代。存储类信息,编译后代码数据等应移存到元空间中。
- 元空间与永久代类似:都是用来规范方法区中的实现。
- 元空间与永久代的差异:元空间不占用虚拟机内存,而是直接占用本地内存。
- 元空间的大小受本地内存的限制。