【JVM】垃圾回收机制

这篇具有很好参考价值的文章主要介绍了【JVM】垃圾回收机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

 哈喽,哈喽,大家好~ 我是你们的老朋友:保护小周ღ  【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收


今天给大家带来的是 JVM (Java 虚拟机) 的垃圾回收机制,回收是指回收什么?  如何确定要回收的内存: 引用计数,可达性分析,如何释放空间 : 标记清除,复制算法,标记整理,分代回收,一起来看看叭~


本期收录于博主的专栏:JavaEE_保护小周ღ的博客-CSDN博客

适用于编程初学者,感兴趣的朋友们可以订阅,查看其它 “JavaEE基础知识”。

更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* ‘


Java运行时内存的各个区域。对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言,其
生命周期与相关线程有关,随着线程的结束而结束。
因为当方法结束或者线程结束时,内存就自然跟着线程回收了。
Java堆中存放着几乎所有的实例对象,垃圾回收器在对堆进行垃圾回收前,首先要判断这些对象哪些还存活,哪些已经 “死去” 。 死去的对象可以简单的理解为:当前对象已经无法使用。

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

上述是一种判断对象是否存活的机制。


一、垃圾回收

垃圾回收(GC),就是帮住程序猿自定的释放内存,在 C 语言中,我们动态开辟的内存(malloc),不使用的时候就需要手动的是调用 free() 方式释放,如果不释放有什么危害呢? 内存是空间是固定的,程序在运行时会向内存申请大量的内存空间,当一些数据,不再使用,也不释放内存,这些无效数据就会一直占据内存的空间,随着无效的数据越来越多,内存逐渐用完,导致内存溢出(抛异常),程序崩溃, 系统宕机的话,重启就好了~

总而言之,内存泄露 是 C/C++ 程序猿职业生涯中的一生之敌。

但是博主是学 Java 的,Java 等后续的编程语言引入了垃圾回收来解决上述问题,能够有效的减少内存的泄露。除非你程序循环\递归申请空间,没有终止条件。

内存的释放是一件比较纠结的事情:

C/C++ 的做法是让程序猿自己决定何时释放内存,依赖于程序猿的水平。

Java 通过JVM 的一些策略自动判定,准确性比较高,但是也意味着在性能上会付出一些代价。


JVM 中的内存有好几个区域, 我们所说的内存回收,具体是回收那一部分的空间呢?

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

程序计数器,就是一个单纯的存地址的整数,用于存储当前正在执行的指令地址或下一条将要执行的指令地址。随着线程的销毁而销毁。

Java虚拟机栈,是Java虚拟机为执行Java方法而提供的一块内存区域,用于支持方法调用和执行。它由栈帧组成,保存了方法的参数、局部变量、返回值等信息。随着方法的结束而结束

本地方法栈,主要维护的是JDK , 内部集成的一些由C/C++ 语言所编写的本地方法或类对象,本地方法栈的大小是可以配置的,可以通过JVM参数来指定。如果本地方法栈空间不足,会抛出栈溢出异常(StackOverflowError)。

方法区(Method Area)是Java虚拟机(JVM)中的一块内存区域,用于存储类的结构信息、常量、静态变量、编译器编译后的代码等数据。它是所有线程共享的,与堆区不同,每个线程都有自己独立的方法栈和程序计数器。

堆区:主要存储就是 类实例后的对象,堆区也是垃圾回收的主要区域。GC 也可以认为是以对象为单位进行释放的。


垃圾回收主要分为两个阶段:这也是主要关注的策略
1. 判断谁是垃圾

2. 删除垃圾的策略


二、确定垃圾

垃圾回收主要是针对堆区上的对象讲述,一个对象如果后续再也不使用了,就可以认为是垃圾。

Java 中使用一个对象,只能通过引用。

如果一个对象,没有引用指向,那么这个对象一定是无法被使用的,就可以认为是垃圾。

如果一个对象, 已经不需要使用了,但是还有引用维护着这个对象,此时并不认为是垃圾。

Java 中只是单纯的判断一个对象有没有引用来维护,来确定是否是垃圾。

Java 对于垃圾对象的标识是保守的,没有及时释放是小,如果不小心干掉了有用的对象,那可能程序都无法继续执行了。

如何判断一个对象是否有引用指向呢?

这里给大家讲解两种策略:  1. 引用计数   2. 可达性分析


2.1 引用计数

引用计数: 给对象安排一个额外的空间,保存一个整数, 表示该对象有几个引用指向。当前这个策略 Java 并没有使用,Python 使用的是引用计数的策略。

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

但是引用计数有两个缺点: 

1. 需要开辟额外的空间来计数。

2. 存在循环引用的情况。会导致引用计数的判定逻辑出错

举个例子:

class Test {
    public Test n; 
}


Test a = new Test();  // 此时 a 引用指向的 Test 对象计数器 = 1
Test b = new Test();  // 此时 b 引用指向的 Test 对象计数器 = 1

a.n = b; // 此时 b 引用指向的 Test 对象又被 a-> Test 的成员n 引用指向, b-> Test 计数器 +1 = 2

b.n = a; // 此时 a 引用指向的 Test 对象又被 b-> Test 的成员n 引用指向, a -> Test 计数器 +1 = 2

如果此时,把 a ,b  引用销毁,那么各自引用的 Test 对象计数器 - 1, 但是 Test 对象的成员变量 n 还保持着引用, 这俩对象的计数器并不是 0 , 不能作为垃圾,但是这俩对象已经无法使用了。这就是陷入了逻辑的循环。

Java 并没有采用引用计数作为确定垃圾的策略,而是使用了可达性分析~

解决引用计数的问题可以采用其他的内存管理技术,如垃圾回收(Garbage Collection)。垃圾回收器可以通过追踪对象之间的引用关系,从根对象开始遍历访问可达对象,将不可达对象标记为垃圾并进行回收。垃圾回收器可以解决循环引用的问题,并且可以在适当的时机自动回收不再使用的内存,减少了手动内存管理的工作量。


2.2 可达性分析 (Java 策略)

可达性分析,把对象之间的引用关系,理解成一个树形结构,从一些特殊的起点出发,进行遍历,要是能遍历到的对象,就是 “可达”, 那么 “不可达” 的当作垃圾处理即可。 

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

上述策略,垃圾回收器可以解决循环引用的问题。

可达性分析的要点:遍历需要有起点,以下可以作为起点。

1. 栈上的局部变量(引用)都是“起点” 都会进行遍历。

2. 常量池中引用的对象

3. 方法区中,静态成员引用的对象。

可达性分析:就是从所以的起点出发,看看该对象里是不是可以访问到其他对象,顺藤摸瓜,把所有可以访问的对象都遍历一遍,遍历的同时把对象标记为 “可达”, 那么剩下的就是 “不可达”就可以认为是垃圾。

可达性分析的缺点: 

1. 因为判断对象是否是垃圾,从起点开始需要进行遍历,这就意味着要消耗更多的时间,而且当某一个对象成为了垃圾,也不一定能够及时的发现。

2. 在进行可达性分析的时候,要从进行顺藤摸瓜,在这个过程中,如果当前代码中的对象引用关系发送了变化,也不能够及时的察觉,所以为了更准确的完成遍历标记,就需要其他业务线程暂停工作(STW 问题),这也是Java垃圾回收机制最大的缺点。


三、释放“垃圾” 对象

通过上述讲解,我们已经知道了Java 如何确定“垃圾”,利用可达性分析。确定垃圾之后就需要对垃圾进行处理。 关于垃圾处理机制,有三种比较典型的策略:

3.1 标记清除

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

使用标记清除,就直接把标志垃圾对象处理里,释放了 ,但是这种方式明显的缺点就是会产生内存碎片,申请空间的时候都是申请 “一块连续的存储空间”,但现在内存的空闲空间是离散的,独立的空间,像这种离散的空间,假设有 1 G , 但是想一次性申请 200M 的空间还不一定能够申请到


3.2 复制算法

复制算法:把整个内存空间,分成两段,一次只使用一半,再把不是垃圾的对象,拷贝到另外一边,然后再统一的释放整个区域。

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

复制算法可以解决内存碎片的问题,同时缺陷也是比较明显的:
1. 一次只是用一半的内存, 对内存的利用率比较低。

2. 如果标记删除的对象比较少,大部分都是要保留的对象,此时将要保留的对象复制到另一边,整个复制的成本是比较高的。


3.3 标记整理

类似于ArrayList (顺序表)删除中间元素,为了保证数据的连续性,有一个搬运的过程。

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

标志整理,解决了内存碎片的问题,也提升了内存的利用率,但是每一次清除标记元素后,搬运数据的开销也是很大的。


根据上述得三种清除标记对象的策略,我们知道,标记清除,会产生内存碎片,复制算法对内存的利用率不高,在要保留的数据很多的情况下,会执行大量的复制操作。标志整理,完美的改善了上述问题,但是又会涉及到大量的数据移动。

因此 JVM 清除标记的实现思路,结合了上述的三种思想 —— 分代回收思想

3.4 分代回收

分代回收,给对象设定了 “年龄“ 的概念,用来描述了这个对象存在了多久。

如果一个对象刚诞生,则认为是 0 岁,每次经过一轮可达性分析,没有被标记的对象就会涨一岁,通过这个年龄来区分这个对象的存活时间。

然后就可以根据不同年龄段的对象采取不同的回收策略。

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

 1.  新创建的对象,放在伊甸区
当垃圾回收(GC)扫描(可行性分析)到伊甸区之后,大部分对象都会在第一轮GC中被淘汰
在年轻代中,主要采用的回收策略是复制算法(Copying Algorithm)和标记-清除算法 (Mark-Sweep Algorithm

 2. 伊甸区中的对象,如果没有在第一轮GC 中淘汰,就会通过复制算法,拷贝到生存区,生存区分为大小相同的两部分,一次只使用其中的一半,当生存区的对象在一轮GC 后被标记,其他幸存的对象就会通过复制算法拷贝到另一块未使用的幸存区,然后清除全部标记对象。如此交替。

 3. 当一个对象在生存区,经过若干论都没有被淘汰,年龄增长到一定的程度,就会通过复制算法拷贝到老年区,进入老年区的对象,被淘汰的概率就很低了,此时针对老年区 GC 的频率也随之降低,如果老年区中发现某个对象是垃圾,就使用标记整理删除。

 4. 特殊情况,当一个对象非常大的时候,是直接进入老年区的(大对象进行复制算法成本比较高)


好了,到这里, 【JVM】垃圾回收机制 博主已经分享完了,这只是简单的概念性的理解,希望对大家有所帮助,如有不妥之处欢迎批评指正。 

【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收

感谢每一位观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* 

遇见你,所有的星星都落在我的头上……【JVM】垃圾回收机制,JavaEE,jvm,垃圾回收,分代回收文章来源地址https://www.toymoban.com/news/detail-705019.html

到了这里,关于【JVM】垃圾回收机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • JVM基础(3)——JVM垃圾回收机制

    JVM基础(3)——JVM垃圾回收机制

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月25日
    浏览(7)
  • 【JVM】垃圾回收机制

    【JVM】垃圾回收机制

     哈喽,哈喽,大家好~ 我是你们的老朋友: 保护小周ღ    今天给大家带来的是  JVM (Java 虚拟机) 的垃圾回收机制,回收是指回收什么?  如何确定要回收的内存: 引用计数,可达性分析,如何释放空间 : 标记清除,复制算法,标记整理,分代回收 ,一起来看看叭~ 本期

    2024年02月09日
    浏览(7)
  • 浅谈JVM垃圾回收机制

    新生代收集(Minor GC/Young GC):只对新生代进行垃圾收集 老年代收集(Major GC/Old GC):只队老年代进行垃圾收集 混合收集(Mixed GC):对整个新生代和老年代进行垃圾收集 收集整个Java堆和方法区 空间分配担保是为了确保在Minor GC之前老年代还有容纳新生代所有对象的剩余空间 垃圾回收算

    2024年02月10日
    浏览(9)
  • JVM及垃圾回收机制

    JVM及垃圾回收机制

    类加载器负责将.class文件加载到JVM中。主要分为三种层次:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader。它们按层次关系加载类,保证类的隔离性和重用性。 运行时数据区包括方法区、堆、栈、本地方法栈和程序计数器。堆用于存放对象实例,方法区保存类信息和

    2024年02月12日
    浏览(6)
  • 【JVM】JVM执行流程 && JVM类加载 && 垃圾回收机制等

    【JVM】JVM执行流程 && JVM类加载 && 垃圾回收机制等

    目录 🌷1、JVM是什么? 🌷2、JVM的执行流程(能够描述数据区5部分) 🌷3、JVM类加载过程 🌷4、双亲委派机制:描述类加载的过程 问题1:类加载器 问题2:什么是双亲委派模型?  问题3:双亲委派模型的优点 🌷5、垃圾回收机制(重要,针对的是堆)    问题1:判定对象

    2024年02月15日
    浏览(9)
  • JVM中的垃圾回收机制

    JVM中的垃圾回收机制

    java相较于c、c++语言的优势之一是自带垃圾回收器,垃圾回收是指 不定时 去堆内存中清理 不可达 对象。不可达的对象并不会 马上 就会直接回收, 垃圾收集器在一个Java程序中的执行是自动的,不能强制执行,程序员唯一能做的就是通过调用System.gc 方法来建议执行垃圾收集

    2024年02月16日
    浏览(47)
  • JVM:垃圾回收机制(GC)

    JVM:垃圾回收机制(GC)

    引用计数算法:         在对象中添加一个引用计数器,当每有一个地方引用它时,计数器值加一。当引用失效时,计数器值就减一。当一个对象的计数器为零时,表示该对象没有被任何其他对象引用,因此可以被释放。 优点 :是可以及时回收垃圾对象,避免内存泄漏,且

    2024年01月19日
    浏览(9)
  • 【JVM】垃圾回收机制详解(GC)

    【JVM】垃圾回收机制详解(GC)

    可以看jvm详解之后,再来理解这篇文章更好 堆和方法区,主要发生在堆中,然后主要发生在堆的伊甸园区(Eden)。 Java中的垃圾回收是根据 可达性分析算法(Reachability Analysis) 和 引用计数算法 来判断对象是否存活的。 JDK.1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:

    2024年02月13日
    浏览(7)
  • 【JVM】| 垃圾回收机制 | 文末送书

    【JVM】| 垃圾回收机制 | 文末送书

    Java的垃圾回收机制是自动的,不需要程序员手动进行内存管理。当Java应用程序创建对象时,它们存储在堆内存中。当对象不再被引用时,垃圾回收器会自动标记这些对象为垃圾,并将它们从堆内存中清除,释放空间。 如果要操作对象,必须通过引用来进行。如果一个对象没

    2024年02月13日
    浏览(6)
  • JVM G1垃圾回收机制介绍

    JVM G1垃圾回收机制介绍

    G1(Garbage First)收集器 (标记-整理算法): Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而其

    2024年02月13日
    浏览(6)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包