java基础 集合 特性

Java内存分配与垃圾回收

2018-07-17  本文已影响39人  WJoe

垃圾收集算法

一、 标记-清除算法(Mark-Sweep)

算法分为“标记”和“清除”两个阶段,首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。标记判定为可达性分析算法。
不足之处有两个:

二、 复制算法(Copying)

为了解决效率问题,出现了复制算法,将可用的容量划分为大小相等的两块,每次使用其中一块,当这块内存用完了,就将还存货的对象复制到另一块上面,然后再把已使用的内存空间一次性清理掉。,内存分配不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。算法代价为内存缩小到原来的一半。

三、 标记-整理算法(Mark-Compact)

复制算法在对象存活率较高时,就要进行较多的复制操作,效率会变低。更关键的是会浪费50%空间。所以老年代一般不能直接选用这种算法。
根据老年代的特点,就提出了一种“标记-整理”算法,整理不是直接对可回收对象进行清理,而是让所有存活对象向一端移动,然后直接清理掉端边界以外的内存。

四、分代收集算法(Generational Collection)

根据对象存活周期的不同,将内存划分为几块。一般是新生代和年老代。新生代采用复制算法。老年代使用“标记—清理”或者“标记-整理”算法。
新生代中的对象98%都是“朝生夕死”的,所以不需要1:1比例来划分内存空间,而是将内存分为一块较大的Eden空间和两个较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden区和Survivor还存活着的对象一次性地赋值到另外一块Survivor空间上,然后清理到Eden和刚刚用过的Survivor空间。

HotSpot算法实现

1、枚举根节点

可达性分析有一个问题就是会导致GC进行时必须停止Java执行线程,因为枚举根节点的时候对象关系不断变化时,分析结果准确性就不能得到保证。即时是CMS收集器,枚举根节点也是必须要停顿的。
在HotStop的实现中,使用一组称为OooMap数据结构来达到这个目的,在类加载的时候HotStop就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用。这样GC在扫描的时候就可以直接得知这些信息了。

2、安全点及安全区域

在OopMap的协助下,HotSpot可以快速且准确的完成GC Roots的枚举,但是HotSpot并没有为每条指令都生成OopMap,因为这样需要的额外空间太多。
而是在特定的位置记录了这些信息,这些位置称为安全点(Safepoint),即程序执行的时候并非在所有的地方都能停顿下来,而是在到达安全段时才能暂停。
安全点的选定基于“是否具有让程序长时间执行的特征”进行选定的。因为每条指令执行的时间都非常短暂,程序不太可能因为指令流长度太长而过长时间运行,“长时间运行”最明显的特征就是指令序列复用。例如方法调用,循环跳转,异常跳转等,具有这种功能的指令才会产生Safepoint。
还有一个问题,如何在GC时使所有的线程都跑到最近的安全点再停顿下来。两个方案

垃圾收集器

图中展示了7种不同分代的收集器:
Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1;

而它们所处区域,则表明其是属于新生代收集器还是老年代收集器:

两个收集器间有连线,表明它们可以搭配使用:
Serial/Serial Old、Serial/CMS、ParNew/Serial Old、ParNew/CMS、Parallel Scavenge/Serial Old、Parallel Scavenge/Parallel Old、G1;

并发垃圾收集和并行垃圾收集的区别

Minor GC和Full GC的区别

1、 Serial收集器

Serial收集器是最基本、发展历史最悠久的收集器。

特点
优点以及应用场景
参数设置

“-XX:UseSerialGC”:添加该参数来显式的使用串行垃圾收集器;

2、ParNew收集器

ParNew收集器是Serial收集器的多线程版本。

特点
应用场景
设置参数
为什么除了Serial只有ParNew能与CMS收集器配合

3、 Parallel Scavenge收集器

Parallel Scavenge收集器是一个新生代收集器,也是使用复制算法以及并行的多线程收集器。它与吞吐量密切相关,也称为吞吐量收集器(ThroughPut Collector)

特点
应用场景
设置参数

四、Serial Old收集器

Serial Old是 Serial收集器的老年代版本;

特点
应用场景

五、 Parallel Old收集器

Parallel Old垃圾收集器是Parallel Scavenge收集器的老年代版本;JDK1.6中才开始提供;

特点
应用场景
设置参数

六、 CMS收集器(Concurrent Mark Sweep)

并发标记清理(Concurrent Mark Sweep,CMS)收集器也称为并发低停顿收集器(Concurrent Low Pause Collector)或低延迟(low-latency)垃圾收集器。

特点
应用场景
设置参数

"-XX:+UseConcMarkSweepGC":指定使用CMS收集器;


CMS收集器运行过程

整个过程中耗时最长的并发标记和并发清除都可以与用户线程一起工作;所以总体上说,CMS收集器的内存回收过程与用户线程一起并发执行;

缺点
总结

总体来看,与Parallel Old垃圾收集器相比,CMS减少了执行老年代垃圾收集时应用暂停时间;
但却增加了新生代垃圾收集时应用暂停的时间、降低了吞吐量而且需要占用更大的堆空间;

七、G1收集器(Garbage-First)

特点
应用场景
设置参数
为什么G1收集器可以实现可预测的停顿?
一个对象被不同区域引用的问题

判断对象存活时,是否需要扫描整个Java堆才能保证准确?在其他的分代收集器,也存在这样的问题(而G1更突出):新生代回收的时候不得不扫描老年代?
无论G1还是其他分代收集器,JVM都是使用Remembered Set来避免全局扫描:
1、每个Region都有一个对应的Remembered Set;
2、 每次Reference类型数据写操作时,都会产生一个Write Barrier暂时中断操作;
3、然后检查将要写入的引用指向的对象是否和该Reference类型数据在不同的 Region(其他收集器:检查老年代对象是否引用了新生代对象);
4、如果不同,通过CardTable把相关引用信息记录到引用指向对象所在Region对应的Remembered Set中;
5、进行垃圾收集时,在GC Roots的枚举范围加入Remembered Set,就可以保证不进行全局扫描,也不会有遗漏。

G1收集器运行过程

这里有一个疑问 筛选回收时会Stop The World嘛?
深入理解JAVA虚拟机第二版中是会的。

内存分配与回收策略

对于Client模式下的JVM来说(只有32位的JDK安装才有Client模式的JVM,64位的JDK只有Server模式的JVM),默认的新生代和老年代的垃圾收集器是单线程的Serial(复制算法,并且存在担保机制,默认Eden区和Survivor是8:1)和Serial Old(标记-整理算法)。下面将研究,在这种组合的情况下,JVM的内存分配和回收策略(ParNew和Serial的组合也差不多)。

上一篇 下一篇

猜你喜欢

热点阅读