Java虚拟机-垃圾回收简介

简介: Java虚拟机-垃圾回收简介

 

image.gif编辑

一、如何判定对象为垃圾对象

-verbose:gc  打印垃圾回收简单信息参数
-xx:+PringDCDetail 打印垃圾回收的详细信息

image.gif

引用计数法

引用计数算法很简单,它实际上是通过在对象头中分配一个空间来保存该对象被引用的次数。如果该对象被其它对象引用,则它的引用计数加一,如果删除对该对象的引用,那么它的引用计数就减一,当该对象的引用计数为0时,那么该对象就会被回收。

采用引用计数的垃圾收集机制中,垃圾收集的开销被分摊到整个应用程序的运行当中了,而不是在进行垃圾收集时,要挂起整个应用的运行,直到对堆中所有对象的处理都结束。因此,采用引用计数的垃圾收集不属于严格意义上的"Stop-The-World"的垃圾收集机制。

引用计数算法有一个比较大的问题,那就是它不能处理环形数据,即如果有两个对象相互引用,那么这两个对象就不能被回收,因为它们的引用计数始终为1。这也就是我们常说的“内存泄漏”问题。

Python中采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略。

可达性分析法

为了引用计数算法中循环引用导致垃圾不会被回收的问题,在Java中采取了 可达性分析法。同样采用此法的还有C#、Lisp(最早的一门采用动态内存分配的语言)。该方法的基本思想是通过一系列的“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。

GC Roots的对象

    • 虚拟机栈(栈帧中的本地变量表)中引用的对象。(可以理解为:引用栈帧中的本地变量表的所有对象)
    • 方法区中静态属性引用的对象(可以理解为:引用方法区该静态属性的所有对象)
    • 方法区中常量引用的对象(可以理解为:引用方法区中常量的所有对象)
    • 本地方法栈中(Native方法)引用的对象(可以理解为:引用Native方法的所有对象)

    二、如何回收

    JVM的内存分代划分

    Java虚拟机将堆内存划分为新生代老年代永久代。

    image.gif编辑

    新生代(Young)

    HotSpot将新生代划分为三块,一块较大的Eden空间和两块较小的Survivor空间,默认比例为8:1:1。划分的目的是因为HotSpot采用复制算法来回收新生代,设置这个比例是为了充分利用内存空间,减少浪费。新生成的对象在Eden区分配(大对象除外,大对象直接进入老年代),当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。

    老年代(Old)

    在新生代中经历了多次(具体看虚拟机配置的阀值)GC后仍然存活下来的对象会进入老年代中。老年代中的对象生命周期较长,存活率比较高,在老年代中进行GC的频率相对而言较低,而且回收的速度也比较慢。

    永久代(Permanent)

    永久代存储类信息、常量、静态变量、即时编译器编译后的代码等数据,对这一区域而言,Java虚拟机规范指出可以不进行垃圾收集,一般而言不会进行垃圾回收。

    回收策略

    1.标记-清除算法(Mark-Sweep)

    算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。

    标记-清除算法的主要缺点:

      • 效率问题:标记和清除过程的效率都不高;
      • 空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,碎片过多会导致大对象无法分配到足够的连续内存,从而不得不提前触发GC,甚至Stop The World。

      image.gif编辑

      2.复制算法(Copying)

      为解决效率问题,“复制”收集算法出现了。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。

      这样使得每次都是对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。

      它的主要缺点有两个:

        • 效率问题:在对象存活率较高时,复制操作次数多,效率降低;
        • 空间问题:內存缩小了一半;需要使用老年代的額外空间做分配担保。

        From Survivor, To Survivor使用的就是复制算法。老年代不使用这种算法。

        image.gif编辑

        3.标记-整理算法

        复制收集算法在对象存活率较高时就要执行较多的复制操作,效率将会变低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。    

        根据老年代的特点,有人提出了另外一种“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。也称为标记-整理-清除算法。

        image.gif编辑

        4.分代收集算法(Generational Collection)

        GC分代的基本假设:绝大部分对象的生命周期都非常短暂,存活时间短。

        “分代收集”算法,把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。

        参考资料:

          1. 引用计数算法 - 简书
          2. JAVA垃圾回收-可达性分析算法_这瓜保熟么的博客-CSDN博客_可达性分析算法
          3. JVM 之(4)垃圾回收算法(标记 -清除、复制、标记-整理、分代收集)_夏目 "的博客-CSDN博客_标记清除算法
          4. Java虚拟机:JVM内存分代策略 - 风中程序猿 - 博客园
          相关文章
          |
          25天前
          |
          监控 算法 Java
          Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
          本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
          32 0
          |
          17天前
          |
          存储 JavaScript Java
          Java 中的 String Pool 简介
          本文介绍了 Java 中 String 对象及其存储机制 String Pool 的基本概念,包括字符串引用、构造方法中的内存分配、字符串文字与对象的区别、手工引用、垃圾清理、性能优化,以及 Java 9 中的压缩字符串特性。文章详细解析了 String 对象的初始化、内存使用及优化方法,帮助开发者更好地理解和使用 Java 中的字符串。
          Java 中的 String Pool 简介
          |
          1天前
          |
          算法 网络协议 Java
          【JVM】——GC垃圾回收机制(图解通俗易懂)
          GC垃圾回收,标识出垃圾(计数机制、可达性分析)内存释放机制(标记清除、复制算法、标记整理、分代回收)
          |
          22天前
          |
          存储 监控 算法
          深入探索Java虚拟机(JVM)的内存管理机制
          本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
          |
          24天前
          |
          存储 监控 算法
          Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
          本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
          |
          28天前
          |
          机器学习/深度学习 监控 算法
          Java虚拟机(JVM)的垃圾回收机制深度剖析####
          本文深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法、性能调优策略及未来趋势。通过实例解析,为开发者提供优化Java应用性能的思路与方法。 ####
          43 1
          |
          21天前
          |
          存储 监控 算法
          Java内存管理的艺术:深入理解垃圾回收机制####
          本文将引领读者探索Java虚拟机(JVM)中垃圾回收的奥秘,解析其背后的算法原理,通过实例揭示调优策略,旨在提升Java开发者对内存管理能力的认知,优化应用程序性能。 ####
          35 0
          |
          2月前
          |
          缓存 算法 Java
          JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
          这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
          89 4
          JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
          |
          3月前
          |
          监控 算法 Java
          深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
          本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
          |
          2月前
          |
          存储 Java PHP
          【JVM】垃圾回收机制(GC)之引用计数和可达性分析
          【JVM】垃圾回收机制(GC)之引用计数和可达性分析
          85 0