jvm回收mysql连接_JVM-垃圾回收

本文详细介绍了JVM中的垃圾回收机制,包括新生代和老年代的垃圾回收器,如Serial、Parallel Scavenge、Parallel New、Serial Old、Parallel Old和CMS。同时讨论了标记-复制和标记-压缩算法。此外,文章还探讨了引用计数算法和可达性分析算法,强调了安全点和Stop-the-world在垃圾回收中的作用,以及如何通过OopMap快速定位GC Roots。文章最后提到了对象死亡的两次标记过程和finalize方法的自我拯救机制。
摘要由CSDN通过智能技术生成

c0264c5bbf85bab3171d329220221b96.png

1. JVM中的垃圾回收器-总览

acfc7ce57d64207a15c0143fe9886e0a.png

针对新生代的垃圾回收器共有三个:Serial,Parallel Scavenge 和 Parallel New。这三个采用的都是标记 - 复制算法。其中,Serial 是一个单线程的,Parallel New 可以看成 Serial 的多线程版本。Parallel Scavenge 和 Parallel New 类似,但更加注重吞吐率。此外,Parallel Scavenge 不能与 CMS 一起使用。

总而言之,当发生 Minor GC 时,我们应用了标记 - 复制算法,将 Survivor 区中的老存活对象晋升到老年代,然后将剩下的存活对象和 Eden 区的存活对象复制到另一个 Survivor 区中。理想情况下,Eden 区中的对象基本都死亡了,那么需要复制的数据将非常少,因此采用这种标记 -复制算法的效果极好。

Minor GC 的另外一个好处是不用对整个堆进行垃圾回收。但是,它却有一个问题,那就是老年代的对象可能引用新生代的对象。也就是说,在标记存活对象的时候,我们需要扫描老年代中的对象。如果该对象拥有对新生代对象的引用,那么这个引用也会被作为 GC Roots。

这样一来,岂不是又做了一次全堆扫描呢?-- 卡表-这个技术是用于解决减少老年代的全堆空间扫描

针对老年代的垃圾回收器也有三个:刚刚提到的 Serial Old 和 Parallel Old,以及 CMS。Serial Old 和 Parallel Old 都是标记 - 压缩算法。同样,前者是单线程的,而后者可以看成前者的多线程版本。

CMS 采用的是标记 - 清除算法,并且是并发的。除了少数几个操作需要 Stop-the-world 之外,它可以在应用程序运行过程中进行垃圾回收。在并发收集失败的情况下,Java 虚拟机会使用其他两个压缩型垃圾回收器进行一次垃圾回收。由于 G1 的出现,CMS 在 Java 9 中已被废弃[3]。

G1(Garbage First)是一个横跨新生代和老年代的垃圾回收器。实际上,它已经打乱了前面所说的堆结构,直接将堆分成极其多个区域。每个区域都可以充当 Eden 区、Survivor 区或者老年代中的一个。它采用的是标记 - 压缩算法,而且和 CMS 一样都能够在应用程序运行过程中并发地进行垃圾回收。

G1 能够针对每个细分的区域来进行垃圾回收。在选择进行垃圾回收的区域时,它会优先回收死亡对象较多的区域。这也是 G1 名字的由来。

即将到来的 Java 11 引入了 ZGC,宣称暂停时间不超过 10ms。如果你感兴趣的话,可参考 R 大的这篇文章[4]。

1.1 总结

1:二八法则-适用于许多的领域,对象在JVM对内存空间的生命周期也同样符合 ( 理想情况下,要进行Minor GC的时候,Eden 区中的对象基本都死亡了)

2:为了更好的JVM性能以及充分利用对象生命周期的二八法则,JVM的作者将JVM的对内存空间进行了分代的处理

3:堆内存空间=年轻代+老年代

年轻代=Eden+from+to

年轻代用于分配新生的对象

Eden-通常用于存储新创建的对象,对内存空间是共享的,所以,直接在这里面划分空间需要进行同步

from-当Eden区的空间耗尽时,JVM便会出发一次Minor GC 来收集新生代的垃圾,会把存活下来的对象放入Survivor区,也就是from区

注意,from和to是变动的

to-指向的Survivor区是空的,用于当发生Minor GC 时,存储Eden和from区中的存活对象,然后再交换from和to指针,以保证下一次Minor GC 时to指向的Survivor区还是空的。

老年代-用于存储存活时间更久的对象,比如:15次Minor GC 还存活的对象就放入老年代中

4:堆内存分代后,会根据他们的不同特点来区别对待,进行垃圾回收的时候会使用不同的垃圾回收方式,针对新生代的垃圾回收器有如下三个:Serial、Parallel Scavenge、Parallel New,他们采用的都是标记-复制的垃圾回收算法。

针对老年代的垃圾回收器有如下三个:Serial Old 、Parallel Old 、CMS,他们使用的都是标记-压缩的垃圾回收算法。

5:TLAB(Thread Local Allocation Buffer)-这个技术是用于解决多线程竞争堆内存分配问题的,核心原理是对分配一些连续的内存空间

6:卡表-这个技术是用于解决减少老年代的全堆空间扫描

2. 引用计数算法

在对象中添加一个引用计数器,每当有一个地方 引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象就是不可 能再被使用的,也就是无用的,需要被回收的

引用计数算法(Reference Counting)虽然占用了一些额外的内存空间来进行计数,但 它的原理简单,判定效率也很高,延迟要比后面介绍的tracing gc要低

内存不太充裕的地方使用引用计数仍然是个合理的选择,后面的tracing gc会要求更高的内存占用.

但是,在Java 领域,至少主流的Java虚拟机里面都没有选用引用计数算法来管理内存,主要原因是,这个看似简单 的算法有很多例外情况要考虑,必须要配合大量额外处理才能保证正确地工作,譬如单纯的引用计数 就很难解决对象之间相互循环引用的问题

扩展: 更高级的引用计数实现会引入“弱引用”的概念来打破某些已知的循环引用

例子:

1 classA {2 privateB b;3 public voidsetB(B b) {4 this.b =b;5 }6 }7

8 classB {9 private A a = newA();10 public voidsetA(A a) {11 this.a =a;12 }13 }14

15 public voidmethod() {16 A a = newA();17 B b

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值