谈谈GC回收机制和算法

- 主要针对堆内存回收

1. 都有哪些GC回收算法 ?

 

Ø 三个问题

² 哪些对象可以回收?

² 如何回收?

² 什么时候回收?

Ø 解决哪些对象可以回收 ?

1) 引用计数器      比较老的算法

原理:对象引用过一次,标记+1;减少一次引用,标记-1;长时间不用,到标记为0的时候 回收

问题:很难解决对象循环引用的问题,就是两个对象相互引用,一致清除不掉

2)可达性分析算法   常用的算法

原理:和GCRoot有关系,留着;没有关系清除;一般只有栈对象,静态变量对象,常量可以当GCRoot.

Ø 解决如何回收?

1) 标记- 清除

问题:会产生大量不连续的内存碎片,大文件存不了,怎么办?在收集一次,还存不了,怎么办?

虚拟内存机制, 将一部分文件存到磁盘IO上;但是不用,影响性能

2) Copying算法

堆内存分成两份,一份块为不可清除状态,一块为可清除状态,1:1的关系,收集内存中的新生代

问题:内存使用率低

改进:1块大的Eden和两块较小的Suivior空间,新创建的放在Eden中;

清除的时候能清除的清除,不能清除的放到Suivivor中,(8:1)  主流使用;

Cpoying算法的改进对提高了内存管理的效率。

新生代存不下,经常存活,把一部分数据存放到老年代.

3) 标记-整理算法

老生代很少发生GC,都是经常用的对象;用在老生带。

内存满之后,将一些不用的,标记移到一块,在删除,不会产生内存碎片

4) 分代收集算法:

将整个堆分成新生代,和老生代,

Ø 谁来回收?

垃圾回收器来回收垃圾

有哪些垃圾回收器?

 

- 新生代   

copying算法

所有的代一直在 革新,但是并没有完全替代

第一代Serial:

Jdk1.3版本,单线程收集器,其它所有线程就要停掉等它完成工作

这个现象不能消除,后续的就是不断优化减少时间的过程

占用内存小的时候使用它是很好的,能提高效率。

第二代:ParNew

Serial的多线程版本

并发收集器,垃圾线程和用户线程同时工作

第三代:Parallel Scavenge收集器

可以达到一个可控制的吞吐量,吞吐量优先收集器

频繁和用户交互的程序不使用

Spark默认用的就是该款收集器,可以在该配置文件中调整 spark-defaults.conf,收集器之间可以组合

- 老年代

Parallel Old,

CMS收集器

以获取最短回收停顿时间为目标的收集器,具于“标记-清除”算法实现

有叫 并发停顿收集器

初始标记 只标记GCroot能关联到的对象,速度很快,用户线程会停顿

并发标记 并发标记阶段,用户线程不会停顿

重新标记 修正并发阶段产生的变化

并发清除 用户线程和垃圾线程同时工作,用户线程不会停顿

和用户交互场景多建议使用,

存在问题:对Cpu的资源非常敏感,无法处理浮动垃圾

因此需要留出一部分空间给浮动垃圾使用,这一部分默认小于10%。

会产生大量内存碎片。

Ø GC算发!

在传统JVM内存管理中,我们把Heap空间分为Young/Old两个分区,Young分区又包括一个Eden和两个Survivor分区,如下图所示。新产生的对象首先会被存放在Eden区,而每次minor GC发生时,JVM一方面将Eden分区内存活的对象拷贝到一个空的Survivor分区,另一方面将另一个正在被使用的Survivor分区中的存活对象也拷贝到空的Survivor分区内。

在此过程中,JVM始终保持一个Survivor分区处于全空的状态。一个对象在两个Survivor之间的拷贝到一定次数后,如果还是存活的,就将其拷入Old分区。当Old分区没有足够空间时,GC会停下所有程序线程,进行Full GC,即对Old区中的对象进行整理。注意:Full GC时,所有线程都暂停,所以这个阶段被称为Stop-The-World(STW),也是大多数GC算法中对性能影响最大的部分。

2. Sparc 内存管理GI回收算法 ?

而G1 GC则完全改变了这一传统思路。它将整个Heap分为若干个预先设定的小区域块,每个区域块内部不再进行新旧分区, 而是将整个区域块标记为Eden/Survivor/Old。当创建新对象时,它首先被存放到某一个可用区块(Region)中。当该区块满了,JVM就会创建新的区块存放对象。当发生minor GC时,JVM将一个或几个区块中存活的对象拷贝到一个新的区块中,并在空余的空间中选择几个全新区块作为新的Eden分区。当所有区域中都有存活对象,找不到全空区块时,才发生Full GC。而在标记存活对象时,G1使用RememberSet的概念,将每个分区外指向分区内的引用记录在该分区的RememberSet中,避免了对整个Heap的扫描,使得各个分区的GC更加独立。

在这样的背景下,我们可以看出G1 GC大大提高了触发Full GC时的Heap占用率,同时也使得Minor GC的暂停时间更加可控,对于内存较大的环境非常友好

              

关于Hotspot JVM所支持的完整的GC参数列表,可以参见Oracle官方的文档中对部分参数的解释。

猜你喜欢

转载自my.oschina.net/u/3754249/blog/1803310
今日推荐