简述java垃圾回收过程_浅析 java 垃圾回收(一)—— 以 HotSpot 为例

java 的垃圾回收也就是我们常说的 gc ( garbage collector )。这是一个老生常谈的问题。之所以这么经常被提及,是因为它对 java 性能有很大影响。

在 c/c++ 中考虑到效率,内存的分配和销毁是由程序员来控制的。程序员使用内存必须手动分配,在使用结束后,在手动释放掉已经不用的内存空间。如果忘记释放内存空间,那么这块内存区域就是一直被占用的状态。其他急需内存的程序将无法使用这块内存,导致内存泄漏。

java 中为了减轻程序员的负担,同时为了防止程序员忘记释放内存导致内存泄漏,内存的回收交由垃圾回收器(gc)管理。程序员可以专注于核心业务的编写,不受繁琐的手动分配和释放的打扰。

gc 所做的工作就是,将不再被使用的对象或者不再被引用的对象,所占用的内存空间进行回收。

为了理解 java 的垃圾回收,先来了解一下 java 内存区域

java 的内存区域粗略包括有5个部分

方法区(Method Area)

虚拟机栈(VM Stack)

本地方法栈(Native Method Stack)

堆(Heap)

程序计数器(Program Counter Register)

146330422293

java 内存区域.png

程序计数器

程序计数器(pc),是 jvm 的一个抽象概念,和 cpu 中的 pc 概念相似。用来记录当前执行的字节码文件的所在行。用来控制程序的执行顺序,进行流程控制。jvm 中的每个线程都拥有一个 pc ,来记录各自执行到的指令位置。

方法区

方法区在 Hotspot JVM 中也称为 permanent generation。与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。 对于习惯在HotSpot虚拟机上开发、部署程序的开发者来说,很多人都更愿意把方法区称为“永久代”(Permanent Generation),本质上两者并不等价,仅仅是因为HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已,这样HotSpot的垃圾收集器可以像管理Java堆一样管理这部分内存,能够省去专门为方法区编写内存管理代码的工作。

虚拟机栈

和 pc 一样,虚拟栈也是线程私有的。生命周期和线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

本地方法栈

本地方法栈和虚拟机栈相似,但是它是用来记录 Native 方法的。也就是 java 调用的非 java 方法,比如 c/c++

堆是 jvm 内存类中的主要部分,被所有线程共享。所有对象和数组都在这个堆上分配,因此堆是 gc 管理的主要区域。为了有效地实现垃圾回收,堆又被细分为新生代(yong generation)和老年代(old generation),新生代又可以再细致地分为 Eden Space 和 Survivor Space。在 Oracle 的 Hopspot JVM 的描述中,也将方法区称为永久代(permanent generation)。

Hotspot 中 gc

JVM 只是 java 虚拟机概念或者称它为标准。就像 rfc 文档和具体网络协议实现的之间关系。因此,JVM 有很多的实现,比如我们最熟悉的两种实现

本文讨论的垃圾回收机制以 HotSpot 为例

HotSpot 中的垃圾回收,主要涉及到 heap ,也就是堆区。

HotsSpot 使用一种叫世代回收(Generational Garbage Collection)的方法来实现垃圾回收,本文的后面将介绍为什么要分代

为了实现世代回收,HotSpot 把 heap 分为多个区域

146330422293

分别为新生代和老年代,对应于垃圾回收的不同过程,使用不同的回收算法

注:

1、有两个垃圾收集过程,minor garbage collection、marjor garbage collection。

2、在进行垃圾回收的时候,会停止所有在运行的线程被称作 " stop world event "

Hotspot 中的垃圾回收有下面几个步骤:

1、新的对象被分配到 eden,两个 survivor 分区在开始状态都是空的

146330422293

2、eden 空间分配满时,就开始执行第一次的 minor garbage collection。将还在被使用的对象移动到 S0,同时删除 eden 中,不再被使用的对象。标记对象 age 为 1。

146330422293

146330422293

3、发生下一次的 minor GC 时,将 eden 区中未被使用的对象删除,并将正在使用的对象移动到 survivor 区。需要注意,这个时候把 eden 对象放到 S1,还把 S0 中还被使用的对象移动到 S1。然后,把 age 加 1。

146330422293

4、再进行下一次 minor GC 时,将 eden 区中未被使用的对象删除,并移动到 S0 区,同时 S1 移动到 S0, age 加 1

146330422293

5、当对象的 age 达到某个阈值(通常情况为 8),就进行 marjor GC 。把 age 为 8 且还在使用的对象,从 yong generation 移动到 old generation

146330422293

6、过程总览

146330422293

为什么要分代?

根据经验分析得到对象特性:

刚创建的对象容易被回收

经过几次回收后还保留的对象,被回收的几率会降低

基于这种分析,可以将堆分为新生代和老生代,针对不同的阶段的特点,采用不同的回收算法来提高回收效率。这就时Hotspot JVM GC 的思想

146330422293

当一个对象经过几次回收后依然存活,对象就会被放入称为老生代的内存空间。在老生代中,几乎所有的对象都是经过几次垃圾回收后依然得以幸存的。因此,可以认为这些对象在一段时期内,甚至在应用程序的整个生命周期中,将是常驻内存的。如果依然使用复制算法回收老生代,将需要复制大量对象。再加上老生代的回收性价比也要低于新生代,因此这种做法也是不可取的。根据分代的思想,可以对老年代的回收使用与新生代不同的标记-压缩算法,以提高垃圾回收效率。(后续讨论算法)

总结

上面简述了 Hotspot JVM 的 GC,但是没有涉及具体的垃圾回收算法。大概的垃圾回收算法有,引用计数法、标记-清除算法、复制算法、标记-压缩法、增量算法*。浅析 java 垃圾回收(二)—— 回收算法继续回收算法

参考

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值