JVM垃圾回收

两种对象存活判定算法:

1.引用计数法:每个对象分配一个引用计数器,在引用数为0时,则可以回收。但是无法解决对象字段互相引用的情况,所以目前商用虚拟机中的垃圾回收器不使用此算法。

2.可达性分析算法:首先枚举虚拟机运行时数据区中所有GC ROOT(虚拟机栈、本地方法栈中的引用,常量池的引用,静态变量引用可以作为GC ROOT);然后从GC ROOT开始分析引用链,如果对象不在引用链中,则表示GC ROOT到该对象不可达,则该对象可回收。

方法区回收

1.回收常量池中常量,以字面常量(字符串)为例,如果字面常量没有被引用,而且有必要的话,就会被清除。常量池的其他符号引用也是一样。

2.回收方法区中的类,判断一个类是否可回收,需要同时满足以下三个条件:①该类的实例被全部回收了。②加载该类的classloader对象被回收了。③该类对应的Class对象没有被引用。但是可以回收,并不代表就会被回收,还要看虚拟机的其他策略。

垃圾收集算法:

1.标记-清除法:①标记了哪些对象是可回收的。②清除哪些可回收的。目前因为效率问题,主流垃圾回收器不用这种算法。主要缺点有:①时间上,标记过程和清除过程的效率较低。②空间上,因为没有整理过程,使用该算法将导致内存碎片化严重,为分配大对象时会很麻烦。这是最基础的算法,以下两种时基于这种算法的缺点改进而成的。

2.标记-整理法:①标记哪些对象是活的。②把活对象移到一端。已分配区域和空闲区域使用一个指示指针分开。分配空间使使用指针碰撞法。这个算法只是把存活对象移到一端而并没有分成两半。

3.复制算法:①标记哪些对象是活的。②算法初期,一般内存分为两个等大的区域,把存活对象复制到没被使用的另一半区域。由于分成两个等大区域的做法使得内存利用率只有50%,所以后来人们把内存区域分成一块较大的Eden空间和两块较小的survivor空间(hotspot中的Eden:Survivor:Survivor的比例是8:1:1,这样的话就是只有一块survivor空间是浪费的,利用率就达到了90%)。每次收集时,把Eden和survivor中的存活对象复制到另一块survivor空间上③一次性清理被使用过区域(如果是第二种的话,就是清理Eden和使用过survivor)。

4.分代收集算法:基于对象的不同生命周期,使用不同的算法。一般分为新生代和老年代。新生代存活率很低,适合使用复制算法,老年代存活率很高,适合使用标记-清除或者标记整理。

区分新生代空间、老年代空间、Eden空间、Survivor空间:

Eden和Survivor是在新生代空间中使用复制算法而划分的空间。即一个新生代空间中,划分为一块较大的Eden空间 和两块较小等大的Survivor空间。对Eden和Survivor的比例确定,是基于新生代中的对象存活率小于10%的经验判断。

 

Hotspot的算法实现

1.枚举GC ROOT

在枚举期间,是需要stop the word的,即挂起所有用户线程。而挂起用户线程分为抢占式和主动式,抢占式即不需要用户线程配合,回收器线程直接中断用户线程;主动式为需要用户线程配合,设置一个标志,用户线程去检查这个标志,为true则主动中断。

2.安全点:

安全点即会生成OopMap(Ordinary Object Pointer)的地方,OopMap存放在引用在栈和寄存器中的偏移量,这样回收器线程就可以根据OopMap快速找到所有GC ROOT。回收器线程进行枚举GC ROOT时,所有用户线程需要停在安全点,安全点一般设在循环中,这样就不会需要运行很久才能到达安全点。

3.安全区域:

安全区域即不会改变引用关系的代码片段,即不用修改OopMap中的内容。这是为了解决在回收器需要用户线程走到安全点时刚好用户线程在阻塞的情况。

 

垃圾收集器

新生代收集器:Serial、ParNew、Parallel Scavenge、G1

老年代收集器:serial old、CMS、Parallel Old、G1

串行:单线程收集器,且收集期间全程stop the world

并行:多线程收集器,收集期间全程stop the world

并发:多线程收集器,收集期间,大部分时间不需要stop the world

收集器最重要的性能指标是用户线程停顿时间和吞吐量。吞吐量即cpu运行用户代码的时间与cpu总耗时的比值。而在这里的明确意思是,虚拟机用户线程运行的时间与虚拟机运行时间的比值,也就是说,假如虚拟机运行了100分钟,而收集器运行了1分钟,那么吞吐量就是99%。用户线程停顿时间主要适用于面对客户的应用,需要良好响应提升用户体验;而吞吐量主要适用于后台运算而不需要太多交互的任务。

1.Serial:串行收集器,使用的是复制算法。单线程的缺点在于不能充分利用cpu资源,好处在于对cpu资源不敏感,不用多线程交互即切换。

2.ParNew:是并行收集器,相当于多线程的Serial,服用了Serial大部分代码。

3.Parallel Scavenge:是并行收集器,但是和Serial、ParNew的框架很不一样。该收集器关注的重点是吞吐量,所以也叫吞吐量优先收集器。该收集器也可根据参数调节停顿时间,主要实现方法是缩小新生代的大小,这将导致Minor GC更频繁。

4.Serial Old:因为该收集器是用于老年代的,所以使用的是标记-整理算法。其他和Serial差不多。

5.Parallel Old:该收集器用于老年代,是Parallel Scavenge的老年代版本。使用标记-整理算法。

6.CMS(Concurrent Mark Sweep):就像它的名字一样,它使用的标记-清除算法。关注重点是停顿时间。该收集器是并发收集器,大部分时间是不需要停顿的。算法的主要步骤有:①初始标记:标记GC ROOT能直接关联的对象。②并发标记:时间较长,该过程是并发的。③重新标记:该过程是停顿的,是并行的,但时间较短,修正并发标记期间的变化。④并发清除:该过程是并发的,清除可回收对象。主要缺点:①对cpu资源敏感,回收器的线程数为(cpu核数+3)/4,如果核数少于4个时并发期间对其他用户线程造成较大影响。②无法收集浮动垃圾:浮动垃圾为标记后,在并发清除期间产生的垃圾。如果CMS运行后,内存空间仍无法满足程序要求,将导致“concurrent mode failure”,此时jvm将启动serial Old进行收集。jdk1.5中CMS启动的阈值为62%,而在jdk1.6中CMS的启动阈值提升到了92%。③碎片化严重:因为该收集器是基于标记-清除算法实现的,所以在回收后导致大量内存碎片。这将给分配大对象时带来麻烦。如果分配大对象时找不到足够大的块,会导致full GC。CMS默认会在顶不住的时候整理内存,但是整理内存的过程是不能并发的,所以停顿时间会延长。

7.G1(Garbage First):G1是一款面向服务器应用的收集器。G1的特点:①与CMS类似,并行与并发。②空间整理,G1整体上是基于标记-整理算法的,从局部(Region之间)上看是基于复制算法的。③分代收集 ④可预测停顿时间,这是相比CMS另一大优势。可预测停顿时间模型是基于将堆区分为多个大小相等的region,新生代和老年代各占一些region。在收集时,在指定的停顿时间内,完成对几个最有价值的region进行回收,而不是像之前的收集器,需要对整个新生代或老年代回收。使用region分区或者分成新生代和老年代都需要面对一个问题,需要只对一个区回收,但是一个区中的对象会引用到另一个区的对象,那么如果只扫描需要回收那个区,引用链是不准确的。那么怎样可以避免扫描整个运行时数据区,收集器是使用Remember Set进行对该区外的引用进行记录。所以每个region都要维护一个RememberSet,如果不分region只是分代,那么新生代和老年代各需维护一个RememberSet。G1运行的主要步骤:①初始标记(串行)。②并发标记(并发)。 ③最终标记(并行)。 ④筛选回收(并行)看到上面的步骤,和CMS很是相似。但CMS是并发回收,G1是并行回收。Sun公司称G1是可以并发回收的,只是并行可以得到更大吞吐量,而且分region回收后,停顿可控,使用并行就好。追求低停顿可尝试用G1代替CMS,但是追求吞吐量的化,G1还不够成熟。

分配和回收策略

1.对象优先在Eden上分配,如果Eden上的空间不够,则进行一次Minor GC;如果GC后存活下来的对象的大小大于survivor空间,则需要把survivor装不下的对象,直接进入老年代。

2.大对象直接进入老年代,回收器有个参数可以设置一个阈值,超过这个大小的对象就直接在老年代分配空间。因为大对象容易使survivor区装不下其他对象,导致经常要使用担保机制把装不下的对象复制到老年代。

3.长期存活的对象将进入老年代,默认年龄为15的对象可以进入老年代,但是也有参数可以设置这个阈值。

4.动态对象年龄判断,在survivor区中的对象,同一年龄的对象的大小大于survivor区的一半,则大于该年龄的对象可以进入老年代

5.空间分配担保,在进行Minor GC前,会进行一次担保,即判断老年代中,最大内存块的大小是否大于新生代中所有对象的大小,或者大于历次新生代进入老年代中的对象大小的平均值,如果真,则进行Minor GC,如果否,则进行一次Full GC。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值