深入理解JVM(四)——垃圾回收算法

深入理解JVM(四)——垃圾回收算法
jvm系列(十):JVM演讲PPT分享

stop the world

会在执行某一个垃圾回收算法的时候产生,JVM为了执行垃圾回收,会暂停java应用程序的执行,等垃圾回收完成后,再继续运行。如果你使用JMeter测试过java程序,你可能会发现在测试过程中,java程序有不规则的停顿现象,其实这就是“stop the world”,停顿的时候JVM是在做垃圾回收。所以尽可能减少stop the world的时间,就是我们优化JVM的主要目标。接下来我们看一下目前有哪些常见垃圾回收的算法。

引用计数法

对一个对象被引用的次数进行计数,当增加一个引用计数就加1,减少一个引用计数就减1。
这里写图片描述
3个Teacher的引用指向堆中的Teacher对象,那么Teacher对象的引用计数就是3,以此类推Student对象的引用计数就是2。
这里写图片描述
Teacher对象的引用减少为2,Student对象的引用减少为0(减少的原因是该引用指向了null,例如teacher3=null),按照引用计数算法,Student对象的内存空间将被回收掉。
原理非常简单,是最原始的回收算法.
但Teacher对象中引用了Student对象,Student对象中又引用了Teacher对象,这种情况下(循环引用),对象将永远无法被回收。

复制算法

 复制算法
缺点:
不适合用于存活对象多的情况,因为那样需要复制的对象很多,复制性能较差,所以复制算法往往用于内存空间中新生代的垃圾回收,因为新生代中存活对象较少,复制成本较低
内存空间占用成本高,因为它基于两份内存空间做对象复制,在非垃圾回收的周期内只用到了一份内存空间,内存利用率较低。

在这里插入图片描述

那么为什么会有两块Survivor,复制算法不是只需要一块Eden和一块Survivor就够了吗?
主要还是为了解决碎片化的问题。假设只有一个Survivor区,当Eden区满的时候,进行Gc,存活对象被分配到了Survivor区,清空Eden区。当再一次Gc完成后,存活的对象继续放在Survivor区,这样不是很美好吗,不会有内存碎片啊!但是别忘了,第一次存到Survivor区的对象很可能在第二次Gc的时候就失活了,清理掉Survivor失活对象不就会产生内存碎片了吗?

标记清除

标记清除算法,它是很多垃圾回收算法的基础

标记:遍历所有的GC Roots,并将从GC Roots可达的对象设置为存活对象;
清除:遍历堆中的所有对象,将没有被标记可达的对象清除;
这里写图片描述
注意上图灰色的对象,因为从GC Root遍历不到它们(尽管它们本身有引用关系,但从GC Root无法遍历到它们),因此它们没有被标记为存活对象,在清除过程中将会被回收。

这里需要注意的是标记清除算法执行过程中,会产生“stop the world”,让java程序暂停等待以保证在标记清除的过程中,不会有新的对象产生。
为什么必须暂停java程序呢?举个例子,如果在标记过程完成后,又新产生了一个对象,而该对象已经错过了标记期,那么在接下来的清除流程中,这个新产生的对象因为未被标记,所以将被视为不可达对象而被清除,这样程序就会出错,因此标记清除算法在执行时,java程序将被暂停。
在这里插入图片描述
因为涉及大量的内存遍历工作,所以执行性能较低,导致“stop the world”时间较长,java程序吞吐量降低;

标记压缩

[外链图片转存失败(img-ZQTwh7bm-1563285859713)(http://ityouknow.com/assets/images/2017/jvm/ppt/jvmppt6.png)]
在标记清除算法的基础上,增加了压缩过程
在进行完标记清除之后,对内存空间进行压缩,节省内存空间,解决了标记清除算法内存不连续的问题。

注意:标记压缩算法也会产生“stop the world”,不能和java程序并发执行。在压缩过程中一些对象内存地址会发生改变,java程序只能等待压缩完成后才能继续。

总结:

垃圾回收算法,这些算法各有各的优缺点,但在JVM中并不是单纯的使用特定的算法,而是使用的一种叫垃圾回收器的东西,垃圾回收器可以看做一系列算法的不同组合,在不同的场景使用合适的垃圾回收器,才能起到事半功倍的效果。

bump-the-pointer和TLAB

快速了解bump-the-pointer和TLAB
jvm 通过bump-the-pointer和TLAB用来加快内存分配。

Bump-the-pointer(撞点)技术跟踪在伊甸园空间创建的最后一个对象,这个对象会被放在伊甸园空间的顶部。如果之后需要创建对象,只需检查伊甸园空间是否有足够的剩余空间。如果有足够的空间,对象就会被创建在伊甸园空间,并且被放置在顶部(此时会更换标记位)。这样一来,每次创建新的对象时,只需要检查最后被创建的对象。这将极大地加快内存分配速度。但是,如果我们在多线程的情况下,事情将截然不同。如果想要以线程安全的方式以多线程在伊甸园空间存储对象,不可避免的需要加锁,而这将极大地的影响性能。

TLABs(Thread-Local Allocation Buffers)–本地线程分配区是HotSpot虚拟机针对多线程下Bump-the-pointer的解决方案。该方案为每一个线程在伊甸园空间分配一块独享的空间,这样每个线程只访问他们自己的TLAB空间,以此在避免加锁的情况下分配内存。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值