JVM垃圾回收
-
GC原理详解
JVM GC只回收堆区和方法区内的对象。而栈区的数据,在超出作用域后会被JVM自动释放掉,所以其不在JVM GC的管理范围内。
GC的主要区域是堆,堆里包含两大块区域,新生代(Young)和老年代(Old)。
默认的新生代(Young generation)、老年代(Old generation)所占空间比例为 1 : 2
Young中包含三块区域,Eden、suvivor1、suvivor2。三块区域默认的空间比8:1:1。下面着重讲解GC的工作过程
- Eden区存放新创建的对象,随着程序的运行,对象增多,占满Eden区。
- Jvm开始第一次GC,新生代的GC叫minorGC。回收掉Eden区可以回收的对象,依然存活的对象放到S0区。
- 第二次GC将Eden和S0区的对象相同的方式放到S1区。将S0变成空闲状态。然后循坏反复,S0 S1进行切换,始终保持一个为空的。如果存在大对象直接放到Old区。
- 经过多次折腾依然存活的对象放到Old区。默认是15次(由参数--XX:MaxTenuringThreshold=15 决定)。
- 当old区空间不足时候会触发Full GC FullGC会很耗时,并且会暂停主线程,因此对系统的性能会造成影响,因此内存越大系统性能也就越好。我们JVM调优也就是减少FullGC的频率。
注意:永久代(方法区)在jdk8之前也会很容易触发FullGC。方法区存放着类的信息。当系统中加载的类或者反射的类太多的时候,永久代内存会不足。
新生代GC用到的算法是复制算法,老年代是标记-整理算法。
-
GC判定算法
-
引用计数法:
在对象中添加一个引用计数器,当有地方引用这个对象的时候,引用技术器得值就+1,当引用失效的时候,计数器得值就-1
算法缺点:当某个引用被收集时,下个引用并不会清0,因此不被回收造成内存泄露。
2.可达性分析:
GCroot结点开始向下搜索,路径称为引用链,当对象没有任何一条引用链链接的时候,就认为这个对象是垃圾,并进行回收。
那么什么是GCroot呢(虚拟机在哪查找GCroot)。
- 虚拟机栈(局部变量表)
- 方法区的类属性所引用的对象。
- 方法区中常量所引用的对象。
- 本地方法栈中引用的对象。
目前主流JVM采用的垃圾判定算法就是可达性分析法。
-
GC回收算法
-
标记-清除算法:
将确定为垃圾的对象进行标记,然后统一回收。
如图所示:黄色的就是被标记清除的。清除后会发现有很多多余的小块。
存在的问题: 1.效率问题 2.内存小块过多。
2.复制算法
将内存区域划分成两块,每次回收时,将依然存活的对象从一块复制到另一块,然后清除不在存活的对象。这样就完成了内存的连续分配,但是引来一个问题。
每次只能使用一半的内存。是不是有点少。。
为了解决这个问题,我们对内存就进行了划分。
我们对内存分为了三块区域。
3.标记-整理算法
复制算法主要针对新生代内存收集方法。
标记-整理算法主要针对的是老年代内存收集方法
然后将右面的进行删除就达到回收效果
标记 - 清除算法: 存在效率问题 & 内存碎片问题
复制算法: 将内存划分为两块大小相等的区域,回收时,把存活的对象复制到另外一块
高效 but 内存缩小了一半
采用此算法回收新生代,一块较大的Eden区和两块较小的Survivor区: 将Eden和Survivor活着的对象一次性复制到另外一个Survivor区
HotSpot默认Eden和Survivor大小8:1
Survivor不够用时 需要老年代空间进行内存分配担保
标记 - 整理算法: 标记后不对可回收对象进行清除,而是让活着的对象向一段移动,然后直接清理掉边界以外的内存
-
垃圾收集器
-
Serial(新生代)
单线程,进行GC时,必须暂停其他工作线程,直到GC结束 Client模式下默认的新生代收集器
2. ParNew(新生代)
Serial的多线程版 Server模式下默认的新生代收集器(与CMS收集器配合)
3. Parallel Scavenge(新生代)
目标是达到一个可控制的吞吐量 可开启GC自适应的调节策略 复制算法 & 多线程
4. Serial Old(老年代)
Serail的老年代版本 标记 - 整理
5. Paraller Old(老年代)
Parallel Scavenge的老年代版本 多线程 & 标记 - 整理
6. CMS(老年代)
7. G1(老年代)
配合使用图:
相关参数:
注:
parallel Scavenge适合后台任务处理,侧重吞吐量,处理更多任务
CMS:低延迟,高响应
CMS 跟 Serial 侧重于低暂停时间 适合实时响应服务.
CMS缺点:吞吐量低