关于JVM的垃圾回收GC的一些记录

目录

一、JVM内存区域划分

 二、从一个基本问题开始引入垃圾回收

三、GC作用的区域

三、如何确定一个对象是否可以被当成垃圾进行回收

(1)引用计数法

(2)可达性分析算法

(3)引用的类型

(3.1)强引用(Strong Reference)

(3.2)软引用(Soft Reference)

(3.3)弱引用(Weak Reference)

(3.4)虚引用(Phantom Reference)

(3.5)终结器引用(Final Reference)

(4)垃圾回收器的大致工作流程

四、垃圾回收算法

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

(2)标记 - 整理算法(Mark Compact)

(3)复制算法

五、堆的不同区域(分代垃圾回收)

六、堆的不同区域使用不同的垃圾回收算法

七、垃圾回收器

1. 有哪些垃圾回收器

2. CMS垃圾回收器和G1垃圾回收器

八、其它一些说明

JVM相关参数


一、JVM内存区域划分

 二、从一个基本问题开始引入垃圾回收

        从一个基本问题思考,既然要进行垃圾回收,那么可定要从某一个区域(内存区域)进行回收(即,把内存区域中的某些对象当成垃圾,把这些垃圾对象占用的内存区域回收回来,从而释放内存,避免这个区域的内存被占满)。

        通过以上一个基本的问题出发,我们可以明确如下几个问题:

(1)在哪个区域上进行垃圾回收(换句话说:JVM的哪个区域可以执行垃圾回收这个动作);

(2)在这个可以执行垃圾回收的区域中,如何识别出哪些对象是垃圾;

(3)确定了哪些对象可以被当成垃圾进行回收,那么应该使用什么算法进行回收;

(4)针对这个可以执行垃圾回收的区域,此区域又可以分为哪些不同的小区域,各个小区域应该使用哪种垃圾回收算法;

        针对以上几个问题,下面逐一进行说明:

三、GC作用的区域

       JVM(Java虚拟机)的垃圾回收主要是针对堆内存进行的。堆内存是用来存储对象实例的地方,而垃圾回收的主要任务就是识别并清除不再被任何活跃对象引用的对象,从而释放它们占用的内存空间。因此,垃圾回收器主要关注的是堆内存中的对象,以确保内存的有效利用和系统性能的提高。

三、如何确定一个对象是否可以被当成垃圾进行回收

        既然已经知道了,垃圾回收是针对堆内存的,那么如何判断堆内存中的哪些对象可以被当成垃圾进行回收呢?有如下几种方法:

(1)引用计数法

        每个对象都会有一个与之关联的引用计数器,用来记录指向该对象的引用数量;当一个对象被引用时,其引用计数加一;当一个对象的引用被释放时,其引用计数减一。当引用计数为0时,表示没有任何引用指向该对象,即可被视为垃圾对象,可以被回收。

        尽管引用计数法简单直观,但也存在一些问题,例如无法处理循环引用的情况(如:当两个或多个对象互相引用导致引用计数不为零)。由于这一缺陷,现代的Java虚拟机一般不再使用引用计数法作为判断对象可以是否被当成垃圾的依据,而是采用基于可达性分析的算法来判断对象是否可以被当成垃圾进行回收。

(2)可达性分析算法

        Java虚拟机中的垃圾回收器采用可达性分析算法来探索所有存活的对象。问题来了,如何进行探索呢?

        是通过扫描堆中的对象,看是否能够沿着 GC Root 对象为起点的引用链找到该对象,找不到,表示可以回收;但是问题又来了,哪些对象可以作为 GC Root对象呢?

        可以使用 Eclipse(没错,就是哪个被IDEA打趴下的Eclipse)提供的一个工具(Memory Analyzer (MAT))进行查看(这个工具需要结合 JDK提供的 jmpa 工具进行使用),MAT分析工具官方下载链接:Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation

(3)引用的类型

        上面提到了<引用>,在Java中,有如下几种引用类型:

(3.1)强引用(Strong Reference)

        强引用是最常见的引用类型,在代码中使用最频繁。当我们使用new关键字创建一个对象时,默认就是强引用。只要强引用存在,垃圾回收器就不会回收被引用的对象。即使内存不足时,系统也会抛出OutOfMemoryError异常而不是回收强引用对象。

        【只有所有GC Roots 对象都不通过【强引用】引用该对象后,该对象才能被垃圾回收】

(3.2)软引用(Soft Reference)

        软引用是一种相对强引用较弱的引用类型。通过SoftReference类来实现。当内存不足时,Java虚拟机会根据一定的策略来决定是否回收软引用对象。通常情况下,只有在内存不足且没有强引用指向该对象时,才会回收软引用对象。软引用适用于对内存敏感的缓存等场景。

        【仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次触发垃圾回收,回收软引用对象】

        【可以配合引用队列来释放软引用自身】

(3.3)弱引用(Weak Reference)

        弱引用(Weak Reference):弱引用是一种比软引用更弱的引用类型。通过WeakReference类来实现。当垃圾回收器进行回收时,无论内存是否充足,只要弱引用对象没有被强引用指向,就会被回收。弱引用常用于实现对象注册表、缓存等场景。

        【仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象】

        【可以配合引用队列来释放弱引用自身】

(3.4)虚引用(Phantom Reference)

        虚引用是最弱的引用类型之一。通过PhantomReference类来实现。虚引用的作用是在对象被回收之前,允许程序员在对象被回收时收到一个系统通知。虚引用无法通过引用访问对象,而是通过ReferenceQueue来获取相关通知。虚引用常与引用队列(ReferenceQueue)一起使用,用于某些特定的清理操作。

        【必须配合引用队列使用,主要配合ByteBuffer使用,被引用对象回收时,会将虚引用入队,由Reference Handler 线程调用虚引用相关方法释放直接内存

(3.5)终结器引用(Final Reference)

        终结器引用是一种比较特殊的引用类型。当对象具有终结器(Finalizer)时,它会被分配给一个终结器引用。终结器引用的主要作用是在对象销毁前,通过执行终结器方法进行资源释放和清理。然而,终结器的使用已不推荐,因为它们具有不确定性和性能问题,应尽量避免使用。

        【无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由Finalizer线程通过终结器引用找到被引用对象并调用它的finalize方法,第二次GC时才能回收被引用对象】

(4)垃圾回收器的大致工作流程

(1)根搜索:垃圾回收器会从一组称为"GC Roots"的起始点开始遍历,例如虚拟机栈中的引用、静态变量等。任何能从GC Roots开始遍历到的对象都被认为是活跃对象,不会被回收;

(2)可达性分析:从GC Roots出发,遍历堆中的对象图,标记所有被引用的对象为活跃对象;

(3)清除阶段:遍历整个堆,将未被标记为活跃对象的对象标记为垃圾,并进行回收。

        注意:JVM使用了不同的垃圾回收算法,例如标记-清除、标记-整理和复制算法等。这些算法的具体实现细节可能会有所不同,但基本的判断原则都是通过可达性分析来确定对象是否可回收。

        此外,Java还提供了finalize()方法,允许对象在被回收之前执行特定的清理操作。但是,由于finalize()方法的执行时机不确定且开销较大,因此在实际应用中,建议使用显式的资源释放方式,如使用try-with-resources语句块来确保及时释放资源。

四、垃圾回收算法

        既然确定了哪些对象可以被当作垃圾进行回收,那么应该使用怎样的方法进行垃圾回收呢?换句话说,使用什么垃圾回收算法呢?

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

示意图:

标记阶段(Marking Phase)

        从根对象(如全局变量和活跃线程的栈和寄存器)开始,通过遍历对象之间的引用关系,标记所有能够被访问到的对象。在这个阶段,所有被标记的对象被视为活动对象,而未被标记的对象则被视为垃圾对象。 

清除阶段(Sweeping Phase)

        标记阶段之后,系统会对堆中的所有对象进行线性遍历,清除未被标记的对象,并将它们所占用的内存空间进行释放。这样就完成了对垃圾对象的回收工作。

优点:

  • 简单直观,能够有效地回收不再使用的内存对象

缺点:

  • 内存碎片化问题和回收效率问题(由于清除阶段释放了大量的内存空间,留下了不连续的内存碎片,可能会导致内存分配时的碎片化问题)
  • 此外,标记-清除算法在执行过程中会停止整个应用程序(Stop the world, STW),可能会导致较长的停顿时间,影响了应用程序的响应速度。

        因此,在实际应用中,往往会结合其他垃圾回收算法,如压缩算法(Compaction)、分代算法(Generational Collection)等,来解决标记-清除算法存在的问题,以提高内存管理的效率和性能。 

(2)标记 - 整理算法(Mark Compact)

示意图:

标记-整理算法有如下几个阶段:

标记(Mark)

        从根对象出发,遍历整个对象图,标记所有活跃对象。活跃对象是指仍然被引用的对象,而非垃圾对象。

整理(Compact)

        将所有活跃对象向内存的一端移动,紧凑排列,以便在后续步骤中形成连续的可用内存空间。

清除(Sweep)

        从堆的另一端开始,将未被标记的对象视为垃圾,将其回收,并释放相应的内存空间。

更新引用:

        在整理过程中,由于对象的位置发生了变化,需要更新所有对对象的引用,确保引用指向正确的内存地址。

优点:

        标记-整理算法的优点是可以大幅减少内存碎片的产生,提高内存的利用率

缺点:

        它需要进行整理和移动对象的操作,可能会引入较大的停顿时间,影响应用程序的响应性能。因此,该算法通常适用于较小的堆内存或对停顿时间要求较低的场景。

(3)复制算法

示意图:

复制算法有如下几个步骤:

  1. 将内存空间分为两个相等的区域:From区和To区。
  2. 在From区中分配内存并创建对象。
  3. 当From区的内存耗尽时,启动垃圾回收机制。
  4. 从From区中将存活的对象复制到To区。
  5. 清空From区中的所有对象,并交换From区和To区的角色。

        复制算法的优点在于简单高效,它解决了标记-清除算法和标记-整理算法中会产生的内存碎片问题。但是,由于需要将存活对象复制到另一块区域,因此复制算法会导致内存利用率降低一半(需要双倍的内存空间),适用于新生代的内存回收,不适合用于老年代的大规模对象回收。

        因此,在JVM中,通常会将堆内存划分为新生代老年代,新生代主要使用复制算法来进行垃圾回收,而老年代则会采用其他更适合的算法,例如标记-整理算法或标记-清除算法。

五、堆的不同区域(分代垃圾回收)

        分代回收算法是JVM的一种垃圾回收算法,基于对象的生命周期,将堆内存分为不同的代(Generation),并对不同代采用适合的垃圾回收算法。通常将堆内存划分为新生代、老年代和持久代(或元数据区),其中新生代又可以进一步划分为Eden区、Survivor区1和Survivor区2

        分代回收算法的主要思想是:大部分对象的生命周期很短,很快就会被回收,而只有少数对象的生命周期很长,需要在堆内存中存活较长时间。因此,我们可以采用不同的垃圾回收算法来针对不同的对象生命周期,以达到更好的性能和效果。

        在分代回收算法中,新生代通常使用复制算法进行垃圾回收,因为大多数对象的生命周期较短,而老年代则采用标记-整理算法或标记-清除算法,因为老年代中的对象生命周期更长,需要更高效的回收算法。而持久代主要存储类元数据信息等不会被回收的数据,一般不需要进行垃圾回收。

        分代回收算法的优点在于根据对象的生命周期采用不同的回收算法,可以更好地平衡垃圾回收的效率和停顿时间(STW),并减少不必要的内存复制和整理操作。但是,分代回收算法需要更多的内存空间来划分不同的代,而且需要更复杂的垃圾回收机制来管理不同代之间的引用关系,因此在实际应用中需要根据具体情况进行选择和配置。

以下是学习黑马视频-JVM教程截的图

六、堆的不同区域使用不同的垃圾回收算法

        通过《五、堆的不同区域(分代垃圾回收)》可知:

  1. 新生代通常使用复制算法进行垃圾回收,因为大多数对象的生命周期较短;
  2. 老年代则采用标记-整理算法或标记-清除算法,因为老年代中的对象生命周期更长,需要更高效的回收算法。
  3. 持久代主要存储类元数据信息等不会被回收的数据,一般不需要进行垃圾回收。

七、垃圾回收器

Oracle官方文档:Available Collectors (oracle.com)

1. 有哪些垃圾回收器

 

2. CMS垃圾回收器和G1垃圾回收器

CMS(Concurrent Mark Sweep)垃圾回收器和G1(Garbage-First)垃圾回收器都是Java虚拟机的垃圾回收器,它们在内存管理和垃圾回收策略上有一些区别。

  1. 并发性能:CMS垃圾回收器是一种以最短停顿时间为目标的垃圾回收器。它使用并发标记和并发清理的方式来实现垃圾回收,可以在垃圾回收过程中与应用程序并发执行,减少停顿时间,提高系统的响应能力。而G1垃圾回收器也具有并发标记和并发清理的特性,但相比CMS,G1进一步改进了并发性能,通过将堆内存划分为多个小块(Region),并采用增量式的方式进行垃圾回收,可以更好地控制每次垃圾回收的时间。

  2. 内存模型:CMS垃圾回收器使用的是分代回收的思想,将堆内存划分为年轻代和老年代。年轻代使用复制算法进行垃圾回收,老年代使用标记-清除算法。而G1垃圾回收器则是基于分区(Region)的内存模型,将整个堆内存划分为多个相等大小的区域,并且不再明确区分年轻代和老年代。G1会根据垃圾回收的情况动态地选择进行回收的区域。

  3. 碎片整理:CMS垃圾回收器在进行垃圾回收时,不会对整个堆内存进行整理,因此可能会导致堆内存的碎片化问题。而G1垃圾回收器采用了分区的方式,并在垃圾回收过程中进行了部分的碎片整理,可以较好地避免堆内存的碎片化问题。【注意:G1垃圾回收器(1)同时注重吞吐量(Throughput)和低延迟(Low latency),默认的暂停目标是 200 ms;(2)超大堆内存,会将堆划分为多个大小相等的 Region;(3)整体上是 标记+整理 算法,两个区域之间是 复制 算法 ;(4)相关JVM参数:< -XX:+UseG1GC >   < -XX:G1HeapRegionSize=size >  < -XX:MaxGCPauseMillis=time >

  4. 停顿时间:CMS垃圾回收器通过并发的方式来减少垃圾回收的停顿时间,但无法完全避免停顿。而G1垃圾回收器则通过控制每次垃圾回收的时间和并发执行的阶段,可以更好地控制全局的垃圾回收时间,并且具有更可预测的停顿时间。

综上所述,CMS垃圾回收器和G1垃圾回收器都是面向低停顿时间的垃圾回收器,但G1相比CMS在并发性能、内存模型、碎片整理和停顿时间上都有进一步的改进和优化。根据具体的应用场景和需求,可以选择适合的垃圾回收器来进行内存管理。

        JDK 1.8默认使用的垃圾回收器是ParallelGC,也称为Parallel Scavenge收集器。这是一种基于标记-复制算法的垃圾回收器,主要针对年轻代进行垃圾回收。ParallelGC使用多个线程并行地进行垃圾回收操作,可以充分利用多核CPU的优势,以提高垃圾回收的效率。

        另外,在JDK 1.8中还引入了G1垃圾回收器,它是一种基于分区(Region)的垃圾回收器,相比于ParallelGC具有更好的并发性能和更可预测的停顿时间。但G1不是默认的垃圾回收器,需要通过特定参数进行配置才能启用。

        需要注意的是,JDK 1.8中的垃圾回收器并不是固定的,可以通过虚拟机参数进行配置。在实际应用中,需要根据具体的场景和需求来选择合适的垃圾回收器。

八、其它一些说明

JVM相关参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/259659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

codevs1219 骑士遍历(棋盘DP)

题目描述 Description设有一个n*m的棋盘&#xff08;2≤n≤50&#xff0c;2≤m≤50&#xff09;&#xff0c;如下图&#xff0c;在棋盘上有一个中国象棋马。 规定&#xff1a; 1)马只能走日字 2)马只能向右跳 问给定起点x1,y1和终点x2,y2&#xff0c;求出马从x1,y1出发到x2,y2的…

java ssh免密登录_SSH公钥、私钥配置(SSH免密码登录方式)

1.首先使用想要发起ssh免密访问的用户A登录Linux(简称客户端Linux)2.进入该用户的家目录(cd ~)&#xff0c;看是否有.ssh文件夹(linux中以.开头文件夹是隐藏的&#xff0c;使用ll -a进行查看)&#xff0c;如果没有则创建(mkdir ~/.ssh)&#xff0c;并修改访问权限(chmod 700 ~…

win8, VS2013 .NET 4.5在哪找svcutil.exe?

我这个纠结呀&#xff0c;公司用win8&#xff0c; .NET 4.5。想做一个很简单的项目&#xff0c;就是wcf宿主iis&#xff0c;项目根目录下有aspx文件和svc文件。于是参考了一个博客http://www.cnblogs.com/yjmyzz/archive/2008/08/19/1270961.html&#xff0c;[原创]WCF入门级使…

Starling 2D框架简介

本系列是对Introducing Starling pdf的翻译&#xff0c;下文是对adobe开发人员中心的一片日志的转载&#xff0c;地址为http://www.adobe.com/cn/devnet/flashplayer/articles/introducing_Starling.html Starling 是在 Stage3D APIs 基础上开发的一种 ActionScript 3 2D 框架&…

Android AutoCompleteTextView控件实现类似百度搜索提示,限制输入数字长度

Android AutoCompleteTextView 控件实现类似被搜索提示&#xff0c;效果如下 1.首先贴出布局代码 activity_main.xml&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res…

java即时聊天系统毕业_(完整版)基于Java即时聊天系统的设计与实现毕业论文设计...

目录1 前言...................................................................................................................................1.1 课题选题背景...................................................................................................…

java与算法_Java与算法之(1) - 冒泡排序

冒泡排序法的原理是&#xff0c;每次比较相邻的两个元素&#xff0c;如果它们的顺序错误就把它们交换过来。例如对4 3 6 2 7 1 5这7个数字进行从小到大的排序&#xff0c;从最左侧开始&#xff0c;首先比较4和3因为是从小到大排序&#xff0c;4和3的顺序显然是错误的&#xff0…

JQuery链式操作简单的菜单列表

看到这个简单的菜单demo&#xff0c;也是为了再看看JQuery对DOM的操作&#xff0c;一直都记不牢&#xff0c;特别是siblings&#xff08;&#xff09;这个总是想不起来。 这次再过一遍JQuery&#xff0c;不管简单的还是复杂的demo 还是坚持练习一遍吧&#xff01;只为记录&…

利用JS实现点击上一周或下一周却换

1.页面加载显示当前年份的第几周 效果如图&#xff1a; html代码&#xff1a; <font size"2" color"black"> <input id"btnweek5" type"button" class"btn" value"上周" οnclick"EduCommissio…

java reference 传引用_Java的引用(reference)---Roni

摘自《Java面向对象编程》一书,作者:孙卫琴 来源:www.javathinker.org在JDK1.2以前的版本中&#xff0c;当一个对象不被任何变量引用&#xff0c;那么程序就无法再使用这个对象。也就是说&#xff0c;只有对象处于可触及状态&#xff0c;程序才能使用它。这就像在日常生活中&am…

C# 以管理员身份运行程序

刚看了一篇博友写的“以管理员身份运行程序”, 所以我也来写一个简单易懂的&#xff0c;简单两步搞定&#xff0c;不用写任何代码&#xff1a; 第一步&#xff1a; 右键选择项目 > 添加 > 新建项 &#xff1b; 找到 应用程序清单文件&#xff0c;后缀名为manifest&#x…

会计转行从事IT,如何在一年时间内全职学习?

2019独角兽企业重金招聘Python工程师标准>>> https://www.zhihu.com/question/21427478/answer/18227060 转载于:https://my.oschina.net/soho00147/blog/836138

如何生成后缀表达式

如果计算一个表达式&#xff0c;比如 456*2&#xff0c;随着计算器的不同&#xff0c;简单的四功能计算器是30&#xff0c;许多科学计算器知道乘法的优先级高于加法&#xff0c;所以科学答案是21。典型计算顺序可以是计算45&#xff0c;存为临时变量a&#xff0c;再计算6*2&…

【原生JS插件】LoadingBar页面顶部加载进度条

先展示一下已经实现的效果&#xff1a; 预览地址&#xff1a;http://dtdxrk.github.io/js-plug/LoadingBar/index.html 看到手机上的浏览器内置了页面的加载进度条&#xff0c;想用在pc上。 网上搜了一下&#xff0c;看到几种页面loading的方法&#xff1a; 1.在body头部加入lo…

qtp启动java程序_转: QTP六脉神剑之调用Java程序

查看( 1147 ) /评论( 21 )六脉神剑之调用程序0Xp1zLN_0版权声明&#xff1a;原创作品&#xff0c;转载请以链接方式注明出自http://www.51testing.com/?35&#xff0c;否则将追究法律责任。51Testing软件测试网y|X,taS51Testing软件测试网b;|w6I"g6oK本文出自songfun的51…

第八章 Python 对象和类

一、什么是对象 在 Pyth 中&#xff0c;对象就是经过实例化的&#xff0c;具体可以操作的一组代码的组合&#xff1b; 对象一般包含数据&#xff08;变量&#xff0c;更习惯称之为属性 attribute&#xff09;&#xff0c;也包含代码&#xff08;函数&#xff0c;也称之为方法&a…

Spring WebSocket初探2 (Spring WebSocket入门教程)

2019独角兽企业重金招聘Python工程师标准>>> WebSocket前端准备 SockJS&#xff1a; SockJS 是一个浏览器上运行的 JavaScript 库&#xff0c;如果浏览器不支持 WebSocket&#xff0c;该库可以模拟对 WebSocket 的支持&#xff0c;实现浏览器和 Web 服务器之间低延迟…

String类的使用 Part2

StringBuilder 类的使用 属性&#xff1a; namespace StringBuilderTest {class Program{static void Main(string[] args){StringBuilder s new StringBuilder("hello,world!");Console.WriteLine(s);//Length属性Console.WriteLine("s.Length{0}", s.Le…

JAVA项目怎么不是蓝色_解决IDEA创建maven项目时pom.xml没有变蓝的问题

如下所示&#xff1a;选中pom.xml&#xff0c;右键点击add as maven project&#xff0c;稍等片刻后就可以了补充知识&#xff1a;Idea导入maven项目不自动识别pom.xml*Idea导入maven项目不自动识别pom.xml*当在idea中导入maven项目时&#xff0c;不能自动识别pom文件解决方法&…

C# 6.0:Expression – Bodied Methods

Expression-bodied 方法是C# 6.0 中另一个能简化代码的特性。我们已经对lambda表达式将funciton和delegation关联起来的这种用法很熟悉了。Expression-bodied 将lambda 表达式的这种用法扩展到了方法上。 像下面代码所示&#xff0c;我们有一个GetTime() 方法返回一个格式化的时…