[Java] 垃圾回收机制 ( Garbage Collection ) 简介

自动垃圾回收( Automatic Garbage Collection )

自动垃圾回收,是指在堆(Heap)内存上分辨哪些对象还在被使用,哪些对象没有被使用,并清除没有被使用的对象。所以,这里的垃圾实际上是指,在内存中,无法再被使用没有存在的价值的但还占据内存空间的对象。

C 语言的内存分配、回收是需要手动完成的,但在 Java 中,回收内存是由垃圾回收器自动完成的。

垃圾回收分为两步骤:1.标记,2.删除。删除垃圾有两种情况,a. 常规删除,b. 带压缩的删除。

第 1 步. 标记 ( Marking )

标记是指垃圾回收器给内存块打上标签,哪些对象有被引用,哪些对象不再被引用

上面的标记前的内存块,下面是标记后的内存块。

被引用的内存是蓝色,没有被引用的是橙色。所有对象都是在标记时期被确定是否有被引用。如果一个系统中的所有对象都需要被扫描,将会很消耗时间。

第 2 步,常规删除

常规删除,会清除没有被引用的对象,保留还在被引用的对象,并指向被清除后的自由内存空间。

上图是常规删除后的情况。

内存分配器持有自由空间的引用,当需要 new 新的对象是,则从自由空间中分配内存。

第 2a 步,带压缩的删除

为了提高性能,除了删除不被引用的对象之外,还可以压缩剩余的还被引用的对象的空间。通过移动剩余的对象,空出一整块的内存空间,方便后期的内存分配。

上图是带压缩删除后的情况。

内存分配器指向一整块空内存的开始位置,有需要的时候,按顺序分配内存即可。

JVM 世代 ( JVM Generations ) 

在前面有提到,标记并压缩 JVM 中所有的对象的效率是很低的。随着对象越来越多地被创建,垃圾回收的时间也会越来越长。根据经验,绝大多数的对象创建不久就会被抛弃,寿命很短。

上面是一个例子。

有图可见,随着时间的推移,仍然被引用的对象越来越少。大多数对象的生命周期都非常短。

根据上面的分析,可通过把堆分世代 ( Generations ) 的方法,来提升 JVM 的性能。堆内存被分为三大块:年轻代( Young Generation ),老年代 ( Old Generation ) ,永久代 ( Permanent Generation )

年轻代 ( Yong Gen ),是所有对象被创建,并变老的地方。当年轻代的空间被塞满时,会引起次垃圾回收 ( minor garbage collection )。次回收能起到优化作用,是基于对象的高死亡率假设。回收一个垃圾对象的年轻代是很快的。幸存下来的内存会变老,并会移到到老年代空间。

老年代 ( Old Gen ),用于存储幸存时间长的对象。通常,有一个阈值,当年轻代的对象的幸存的时间超过阈值,则会被移到老年代。到最后,老年代的存储也会被回收,这一过程称为主垃圾回收( major garbage collection )。

暂停全世界的事件 ( Stop the World Event ),次垃圾回收和主垃圾回收都属于暂停全世界的事件。暂停全世界的事件是指,应用的所有线程都会暂停,直到该事件完成。

通常,主回收会很慢,因为它涉及所有的对象。所以,对于高响应的应用,应当尽量避免主回收事件。JVM 提供了有多种类型的垃圾回收器。老年代的垃圾回收器的选择,会影响主回收引起的暂停全世界事件的时间长短。

永生代 ( Permanent Gen ),包含了 JVM 用到的,用于描述应用中类和方法的元数据( metadata )。在运行时,JVM 根据所用到的类,填充永生代空间的内容。Java SE 库中的类和方法也可能存于永生代。永生代对应的是类级别的内存。

当 JVM 发现一个类不在被使用,空间需要回收用于其他类是,该类的空间可能会回收。Full garbage collection 会覆盖到永生代的空间。

 参考资料

Describing Garbage Collection, Java Garbage Collection Basics 

原文地址:https://www.cnblogs.com/TonyYPZhang/p/5615600.html