来说说垃圾回收怎么样~

来说说垃圾回收怎么样~

作者: 鸭血粉丝 2020-11-27 07:45:31

云计算

虚拟化 JVM 的自动内存管理,让原本应该是开发人员去做的事情,变成了垃圾回收器来做的事情,既然是别人帮忙做的事情,那么可能就不是自己想要的,所以就需要我们了解一下垃圾回收相关的内容。

[[354376]]

本文转载自微信公众号「Java极客技术」,作者鸭血粉丝 。转载本文请联系Java极客技术公众号。  

JVM 的自动内存管理,让原本应该是开发人员去做的事情,变成了垃圾回收器来做的事情

既然是别人帮忙做的事情,那么可能就不是自己想要的,所以就需要我们了解一下垃圾回收相关的内容

引用计数法与可达性分析

垃圾回收,垃圾回收,那就是有的内存分配给了一些对象,但是这些对象已经用完了,那么它所占用的内存也就应该该释放掉了,却还没有释放

那么,这里就有个问题:该如何确定一个对象用完了呢?

其中一种方法就是引用计数法

引用计数法就是给每个对象添加一个引用计数器,来统计指向该对象的引用个数

比如:如果有一个引用,被赋值为某一个对象,那么这个对象的引用计数器就 +1 ,如果一个指向这个对象的引用,被赋值为了其他的值,那么这个对象的引用计数器就 -1 ,这样如果这个对象的引用计数器为 0 ,我们就可以认为这个对象已经使用完毕,它所占用的内存空间可以回收掉了

这种方案听上去无懈可击,但是有一个致命的漏洞,就是没办法处理循环引用的问题

比如说: A 和 B 互相引用,除此之外也没有其他的引用指向 A 或者 B ,在这种情况下,其实 A 和 B 所占用的内存就可以释放掉了,但是因为它们互相都有引用,所以此时的引用计数器并不为 0 ,在这种情况下,就不能对它们进行回收

现在只是两个对象,如果再来两个,再来两个,这样循环引用的对象多了之后,就会造成内存泄露

基于引用计数法的弊端,当前 JVM 主流的垃圾回收器采取的是可达性分析算法

这个算法本质就是将一系列的 GC Roots 作为初始的存活对象合集( live set ),然后从这个合集出发,探索所有能够被该集合引用到的对象,并把这些对象加入到集合中来,这个过程就叫做标记( mark ),遍历到最后,没有被探索到的对象就是可以回收的对象

那么什么是 GC Roots 嘞?一般包括(但不限于)以下几种:

  • Java 方法栈桢中的局部变量
  • 已加载类的静态变量
  • JNI handles
  • 已启动并且没有停止的 Java 线程

刚才说因为引用计数法存在循环引用的问题,所以目前主流垃圾回收器选用的都是可达性分析法,也就是说,它解决了循环引用问题,其实这一点也比较好理解,虽然 A 和 B 相互引用,但是这个时候从 GC Roots 开始出发,是没有办法到达 A 和 B 的,那么就不会把它们放到存活对象合集之中,自然也就会被回收掉

但是在实际中还是会有问题的,比如:在多线程环境下,就会有其他线程更新已经访问过的对象中的引用,但是是多线程并行的嘛,这个时候可达性分析法已经把这个引用设置成了 null ,或者这个对象还在使用,但可达性分析法把它标记为了没有被访问过的对象,被回收掉了,这种情况可能直接导致 JVM 崩溃掉

Stop-the-world & safepoint

既然可达性分析法也有自己的一些缺陷,总得有解决方案吧?比较暴力的一种方法就是 Stop-the-world ,估计听名字也能知道,就是让全世界都停下来,也就是说,在进行垃圾回收的时候,其他所有非垃圾回收线程的工作都需要停下来,先让垃圾回收器工作完毕再说。这就是所谓的暂停时间( GC pause )

Stop-the-world 是通过安全点( safepoint )机制来实现的。啥意思嘞?咱先想个场景,现在你敲代码敲的特别开心,又有思路,状态又好,美滋滋的正在工作,突然毫无缘由的就让你现在不准敲代码,你会不会不开心?好不容易思路来了对吧,就一点儿理由都不给的就让我停下,不合理吧?

同样的场景,一个线程现在跑的特别 happy ,而且再有一秒钟就完成了任务,这个时候 JVM 收到了 Stop-the-world 请求,二话不说就把所有的线程给停掉,不太好吧?那么这个时候安全点( safepoint )机制就登场了。有了安全点机制,当 JVM 收到 Stop-the-world 请求的时候,它就会等待所有的线程都达到安全点,才允许请求 Stop-the-world 的线程进行独占的工作

那么,什么时候是安全点呢?举个例子来说:当 Java 程序通过 JNI 执行本地代码时,如果这段代码不访问 Java 对象,不调用 Java 方法,不返回到原 Java 方法,那么 Java 虚拟机的堆栈就不会发生改变,那这段本地代码就可以作为一个安全点。只要不离开这个安全点, JVM 就可以在垃圾回收的同时,继续运行这段本地代码

因为本地代码需要通过 JNI 的 API 来完成上述三个操作,因此 JVM 只需要在 API 的入口处进行安全点检测( safepoint poll ),看看有没有其他线程请求停留在安全点这里,就可以在必要的时候挂起当前线程

垃圾回收的三种方式

当标记好存活的对象之后,就可以进行垃圾回收了

主流的垃圾回收方式,可以分为三种:清除( sweep ),压缩( compact ),复制( copy )

清除,就是把死亡对象所占据的内存标记成空闲内存,并把它记录在一个空闲列表( free list )中,当需要新建对象的时候,就直接在空闲列表中寻找空闲内存,划分给新建的对象就完了

但是这里会产生一个问题,因为死亡的对象所占据的内存可能是随机的,回收完毕之后,内存就是碎片化的,如果此时有对象申请一块连续的内存空间,尽管碎片化的内存空间是够用的,也没办法进行分配

压缩,就是把存活的对象聚集到内存区域的起始位置,这样就可以留下一段连续的内存空间。这样去做的话,可以解决内存碎片化的问题,代价就是压缩算法带来的性能开销

复制,就是把内存区域分成两等分,分别用两个指针 from 和 to 来维护,并且只是用 from 指针指向的内存区域来分配内存。当进行垃圾回收时,就把存活的对象复制到 to 指针指向的内存区域中,并且交换 from 指针和 to 指针的内容。

复制这种方式也可以解决内存碎片化的问题,但是它的缺点也是比较明显的,因为把内存区域分成了两等分嘛,那利用率就比较低咯,最高也是 50% 了,不能再高了

垃圾回收在 JVM 中的应用

上面说的三种垃圾回收方式是理论上的,那么在 JVM 中是如何应用的呢?

这就先要来了解下 JVM 的堆划分,大概就是这样子:

JVM 将堆划分为新生代和老年代,在新生代中又划分为 Eden 区,还有两个大小相同的 Survivor 区

当程序调用 new 指令时,会在 Eden 区中划出一块作为存储对象的内存,但是因为堆空间是线程共享的,所以在这里面划分空间的话就需要同步,要不然出现了两个对象共用一段内存,那不就该打架了嘛

JVM 为了避免两个对象打架的事情发生,就让每个线程向 JVM 申请一段连续的内存,来作为线程私有的 TLAB ( Thread Local Allocation Buffer ,对应虚拟机参数 -XX:+UseTLAB ,默认开启的)

Eden 区一直进行分配,总有空间分配完毕的时候,该怎么办?此时 JVM 就会触发一次 Minor GC ,来收集新生代的垃圾,存活下来的对象就会被送到 Survivor 区

在图中可以看到, Survivor 区有两个,一个是 from ,一个是 to ,其中 to 指向的 Survivor 区是空的

当发生 Minor GC 时, Eden 区和 from 指向的 Survivor 区中的存活对象会被复制到 to 指向的 Survivor 区,然后交换 from 和 to 指针,这样就保证了下一次 Minor GC 时, to 指向的 Survivor 区还是空的

同时 JVM 会记录 Survivor 区的对象一共被来回复制了几次,如果一个对象被复制的次数为 15 (对应虚拟机参数 -XX:+MaxTenuringThreshold ),这个对象就会被晋升( promote )到老年代

那么在发生 Minor GC 时,采用哪种垃圾回收方式会比较好一些呢?采用复制方式,也就是 标记-复制 算法会好一些。为什么呢?因为在新生代中,大部分的 Java 对象只存活一小段时间,那么我们就可以采用耗时比较短的垃圾回收算法,让大部分的垃圾都能在新生代被回收掉。使用 标记-复制 算法的话,理想情况下就是 Eden 区中的对象基本都死亡了,那么需要复制的数据非常少,此时这种算法的优势就被极大的体现了出来

 

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/286782.html<

(0)
运维的头像运维
上一篇2025-05-15 12:38
下一篇 2025-05-15 12:39

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注