美文网首页
深入理解 Java 内存回收机制

深入理解 Java 内存回收机制

作者: zhengaoly | 来源:发表于2021-09-18 10:22 被阅读0次

JVM 通过 GC(Garbage Collection,垃圾回收器)来回收堆和方法区中的内存,这个过程是自动执行的。说到 Java GC 机制,其主要完成 3 件事:确定哪些内存需要回收;确定什么时候需要执行 GC;如何执行 GC。JVM 主要采用回收器的方式实现 GC,主要的回收器有引用计数回收器和跟踪回收器。

一、引用计数回收器

(1)引用计数器采用分散式管理方式,通过计数器记录对象是否被引用。当计数器为 0 时,说明此对象已经不再被使用,可进行回收。如图所示:

image

(2)引用计数器需要在每次对象赋值时进行引用计数器的增减,所以有一定消耗。另外,引用计数器对于循环引用的场景没有办法实现回收。例如在上面的例子中,如果 Object_2 和 Object_3 互相引用,那么即使 Object_1 释放了对 Object_2 和 Object_3 的引用,也无法回收 Object_2、Object_3,因此对于 java 这种会形成复杂引用关系的语言而言,引用计数器是非常不适合的。

二、跟踪回收器

跟踪收集器采用的是集中式的管理方式,会全局记录数据引用的状态。它基于特定的触发条件(例如定时、空间不足时),执行时需要从根集合来扫描对象的引用关系,这可能会造成应用程序暂停。主要有复制(Copying)、标记 - 清除(Mark-Sweep)和标记 - 压缩(Mark-Compact)三种实现算法。
1. 复制(Copying)
复制采用的方式为从根集合扫描出存活的对象,并将找到的存活对象复制到一块新的完全未被使用的空间中,如图所示:

image

复制收集器方式仅需要从根集合扫描所有存活对象,当要回收的空间中存活对象较少时,复制算法会比较高效(年轻代的 Eden 区就是采用这个算法),其带来的成本是增加一块空的内存空间以及需要进行对象的移动。

2. 标记 - 清除(marking-delete)
标记 - 清除采用的方式是从根集合开始扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未标记的对象,并进行清除,标记和清除过程如下图所示:

image

上图中蓝色的部分是有被引用的存活的对象,褐色部分没被引用的可回收的对象。在标记阶段为了标记对象,所有的对象都会被扫描一遍,扫描的过程是比较耗时的。

image

清除阶段回收的是没有被引用的对象,存活的对象被保留。内存分配器会持有空闲空间的引用列表,当有分配请求时会查询空闲空间引用列表进行分配。标记 - 清除动作不需要进行对象移动,只需要对不存活的对象进行处理。在空间中存活对象较多的情况下较为高效,但由于标记 - 清除直接回收不存活对象占用的内存,因此会造成内存碎片。

3. 标记 - 压缩(Mark-Compact)
标记 - 压缩和标记 - 清除一样,是对活的对象进行标记,但是在清除后的处理不一样,标记 - 压缩在清除对象占用的内存后,会把所有活的对象向左端空闲空间移动,然后再更新引用其对象的指针,如下图所示:

image

很明显,标记 - 压缩在标记 - 清除的基础上对存活的对象进行了移动规整动作,解决了内存碎片问题,得到更多连续的内存空间以提高分配效率,但由于需要对对象进行移动,因此成本也比较高。

4. 分代式垃圾回收

分代收集算法是目前大部分 JVM 的垃圾收集器采用的算法。它的核心思想是是分而治之,根据对象存活的生命周期将内存划分为若干个不同的区域,再根据不同区域的特点来具体选择合适的垃圾回收方案。一般情况下,根据对象易产生垃圾的状态或者对象的大小,将堆区划分为老年代(Tenured Generation)和新生代(Young Generation)。堆内存分代策略如图所示。

image

(1)新生代也称 Young 区。新生代划分为一块较大的 Eden 空间(伊甸园)和 Survivor 空间(幸存者区)。eden 区也称伊甸园(《圣经》中亚当和夏娃出生的地方),很形象的比喻对象的出生地点,全部的新生对象都会出现在 eden 区。在 Survivor 幸存者空间中又分为 from 和 to 两块 (也称为 s0 和 s1),用于相互复制对象来进行垃圾清理。新生代的绝大部分对象有朝生熄灭的特点,存活率很低,每次垃圾回收时都有大量的对象需要被回收。目前大部分垃圾收集器对于新生代都采取复制回收算法,因为新生代中的对象创建时间不长,更新比较快。每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少。当进行回收时,将 Eden 和其中一块 Survivor 中还存活的对象复制到另一块 Survivor 空间中,然后清理掉 Eden 和刚才使用过的 Survivor 空间,如此循环下去。

(2)老年代也称 Old 区。老年代存放的是一些 “大对象” 以及新生代中经过多次垃圾回收仍然存活的对象。老年代中对象的生命周期较长,对象存活率较高。每次垃圾收集时只有少量对象需要被回收,产生垃圾少。针对这种情况,使用标记 - 压缩算法回收效率比较高。

(3)持久代也称 Permanent 区或方法区。存储类信息、常量、静态变量以及方法描述等信息。相对而言,垃圾回收行为在这个区域是比较少出现的,但并非数据进入了持久代就可以永久存在。对永久代的回收主要回收两部分内容:废弃常量和无用的类。

(4)分代垃圾回收过程如图所示

image

相关文章

  • Java垃圾回收详解

    深入理解 Java 垃圾回收机制 深入理解 Java 垃圾回收机制 一:垃圾回收机制的意义 java 语言中一个...

  • Java垃圾回收

    本文主要摘自《深入理解Java虚拟机》,内容较多,尽量全面概括了 Java 垃圾回收机制、垃圾回收器以及内存分配策...

  • Java内存回收初探

    要深入的理解Java内存回收的机制,我认为要从以下几个方面去学习,首先了解JVM虚拟机内存分为哪几块,知道Java...

  • JVM之Java垃圾回收机制

    为大家推荐一篇写的通俗易懂的关于Java垃圾回收机制的文章理解Java垃圾回收机制 Java主要把内存分为堆内存和...

  • 对 Java 内存的一些理解-[Android_YangKe]

    Java 垃圾回收机制优点 Java 内存模型 什么是内存抖动 什么是内存泄漏 垃圾回收机制常见算法 Java 垃...

  • 安卓技能点

    技术方面: 掌握Java开发,以及对JVM以及Java内存管理,java内存区域与溢出、垃圾回收有较深入的理解; ...

  • 深入理解 Java 内存回收机制

    JVM 通过 GC(Garbage Collection,垃圾回收器)来回收堆和方法区中的内存,这个过程是自动执行...

  • Java内存管理机制 ————浅析原理

    java内存管理机制 内存泄漏 内存溢出 内存抖动: 话术整理 首先java的内存管理机制 gc的垃圾回收...

  • 06 性能优化-内存优化-内存的分配和回收机制

    1 Java内存分配机制和回收机制 1.1、Java的内存分配区域 Java内存分配主要包括以下几个区域: 方法区...

  • Android知识大纲

    Android知识大纲 Java垃圾回收机制 Java内存是如何划分的,Java语言为什么要使用垃圾回收机制? 垃...

网友评论

      本文标题:深入理解 Java 内存回收机制

      本文链接:https://www.haomeiwen.com/subject/civegltx.html