jvm的垃圾回收_垃圾回收机制原理

jvm的垃圾回收_垃圾回收机制原理通常,我们在写java程序的时候,似乎很少关注内存分配和垃圾回收的问题。因为,这部分工作,JVM已经帮我们自动实现了。这样看起来,好像很美好,但是任何事情都有两面性。虽然JVM会自动的进行垃圾回收,但是,如果遇到有些问题,JVM自己也处理不了呢?因此,我们需要了解一下JVM垃圾回收是怎样运作的,这样才能在遇到问题的时候,有的放矢。所以,今天就来聊一聊JVM的垃圾回收吧。首先,思考一下,为什么…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

通常,我们在写java程序的时候,似乎很少关注内存分配和垃圾回收的问题。因为,这部分工作,JVM已经帮我们自动实现了。

这样看起来,好像很美好,但是任何事情都有两面性。虽然JVM会自动的进行垃圾回收,但是,如果遇到有些问题,JVM自己也处理不了呢?

因此,我们需要了解一下JVM垃圾回收是怎样运作的,这样才能在遇到问题的时候,有的放矢。所以,今天就来聊一聊JVM的垃圾回收吧。

首先,思考一下,为什么需要进行垃圾回收?

我们知道,在创建对象的时候,Java会把对象的内容放到堆中。随着时间的推移,堆中的对象肯定会越来越多,但是,堆的大小是有限制的。如果,我们不进行垃圾回收,也就是把无用的对象进行清除和回收,那么JVM将不堪重负,最终导致内存泄漏。

既然我们需要进行垃圾回收,那么,首先得知道什么是垃圾。

在垃圾收集器对堆内存进行回收前,会先判断哪些对象还在“存活”,哪些对象已经“死去”(即不可能再被任何途径使用的对象),这些“死去”的对象,就是我们需要进行回收的垃圾。

那么,通过什么方式去判定是否为垃圾呢?(即判定对象是否存活)

引用计数算法(已淘汰)

引用计数算法,是指给对象中添加一个引用计数器,每当有一个地方引用它时,计数器的值就加1,当引用失效时,计数器的值就减1。当计数器值为0时,该对象就会被回收。

可以说,引用计数算法的实现非常简单,判定效率也很高。但是,我们忽略了一个问题,在Java中,对象之间是可以互相循环引用的。如果,两个对象之间互相循环引用,那么就会导致,它们之间的引用计数都不为0(都在等待对方释放资源),因此,就无法通知垃圾收集器回收它们。

可达性分析算法

这个算法的思想就是,通过一系列被称为“GC Roots”的对象作为起点,然后向下搜索,所走过的路径被称为引用链。当一个对象到 GC Roots之间没有任何引用链时(即从GC Roots到该对象不可达),则证明该对象是不可用的。

jvm的垃圾回收_垃圾回收机制原理

这个算法解决了循环引用的问题,只要对象无法与GC Root之间建立直接或间接的连接,就会判定为可回收对象。

那么,什么对象可以作为GC Root呢?一般分为以下四种:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  2. 方法区中类静态属性引用的对象。
  3. 方法区中常量引用的对象。
  4. 本地方法栈中引用的对象。

既然已经确定了哪些垃圾可以被回收,那么就需要垃圾收集器进行垃圾回收了,我们来了解一下几种比较常见的的垃圾收集算法。

标记清除算法

file

是最基础的一种收集算法,分为标记和清除两个阶段。首先,把需要回收的对象标记出来,然后再把他们清除掉。如上图所示,所有可回收的对象会变成未使用的一片区域。

标记清除算法逻辑清晰,易于操作。但是,我们可以看到,未使用的内存区块都不是连续的,因此,此算法会产生很多的内存碎片。这样,当一些较大的对象需要分配空间的时候,就找不到足够的连续内存来存储,因此会提前触发GC,同时也浪费了很多的内存空间(内存空间太小,导致不可用)。

复制算法

file

复制算法,是指把内存区域划分为大小相等的两块区域。每次只使用其中的一块,当这一块内存用完了,就把所有存活的对象复制到另一块上面,最后再把已使用过的内存空间一次清理掉。

这样,就可以保证内存区域的连续性,不会产生内存碎片,实现简单,运行高效。但是,这样的话只有使用原来一半的内存,代价也太高了。

标记整理算法

file

标记整理算法,标记过程和标记清除算法一样,但是后续不是进行清除,而是先整理,让所有存活的对象都向一端移动,然后再清除另一端的内存区域。

标记整理算法解决了标记清除算法产生内存碎片的问题,同时也解决了复制算法只能利用一半内存的问题,看似是非常的完美。但是,它却产生了另外一个问题。可以看到图中,内存的变动非常频繁,每次整理都有很多存活的对象内存地址发生改变。因此,它的效率会慢很多。

所以,现在一般用分代收集算法。在Java堆中,分为新生代和老年代,可以根据各个代的特点,选择最合适的收集算法。新生代中,每次垃圾收集都有大批对象死去,只有少量对象存活,就可以选择复制算法,只需要付出少量存活对象的复制成本即可。而老年代中,对象存活率高,没有额外空间对它进行分配担保,因此使用标记清除或者标记整理算法。

堆内存模型

Java堆是内存管理中最大的一块区域,也是垃圾回收的重点区域。堆分为新生代、老年代和永久代,新生代又分为Eden区和Survivor区,Survivor又分为S0和S1区。在JDK1.8之后把永久代移除了,而用元空间代替。(永久代使用的是堆内存,而元空间直接使用本机物理内存)

file

新生代中的对象98%都是朝生夕死的,因此把新生代分为较大的一块Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor(此处Survivor区也叫From区,另一块空的未使用的空间叫To区,From和To区是会交换的,保证空的总是To区)。

当Eden区没有足够的空间分配时,会进行一次Minor GC,Eden区大部分对象都被回收,而Eden区和From区存活的对象会放入到To区,然后From和To区进行交换。(如果To区空间不够,直接进入老年代)

以下几种情况会进入老年代。

1) 大对象

大对象就是指需要大量连续内存空间的对象,最典型的就是那种很长的字符串和数组。大对象会直接进入到老年代,这样做的目的主要是为了避免新生代发生大量的内存复制(大对象的复制成本较高)。

2)长期存活的对象

虚拟机给每个对象都定义了一个对象年龄计数器。每当进行一次Minor GC,年龄就增加1岁,当年龄超过一定值时(默认是15,可以通过参数配置),就进入到老年代。

3)动态对象年龄判断

虚拟机并不要求对象年龄一定要到达15岁才进入到老年代。如果Survivor空间中有某年龄相同的所有对象大小总和大于Survivor空间的一半,则年龄大于等于该年龄的对象就会直接进入老年代。

空间分配担保

在发生Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果大于,那么Minor GC可以确保是安全的(因为,极端情况下,就算新生代所有对象都存活,也可以保证安全晋升到老年代)。否则,虚拟机会查看HandlePromotionFailure的值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小。如果大于,将尝试进行一次Minor GC(尽管有风险);如果小于或者HandlePromotionFailure设置不允许冒险,那么就先进行一次Full GC。

以上说的有风险,是因为取历次晋升到老年代对象的平均值这种方式只是经验值,并不能保证每次都能担保成功,如果担保成功还好,如果担保失败的话,依然需要进行Full GC。

尽管如此,我们最好还是打开HandlePromotionFailure开关,避免过多频繁的Full GC(因为Full GC的执行速度比Minor GC慢的多)。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/194745.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • dede list列表页和文章页分别使用if else

    dede list列表页和文章页分别使用if else

    2021年9月19日
    36
  • java怎样编写程序_makefile编写实例

    java怎样编写程序_makefile编写实例最近准备花费很长一段时间写一些关于Java的从入门到进阶再到项目开发的教程,希望对初学Java的朋友们有所帮助,更快的融入Java的学习之中。主要内容包括JavaSE、JavaEE的基础知识以及如何

    2022年8月4日
    6
  • ZigBee协议栈简介和流程「建议收藏」

    ZigBee协议栈简介和流程「建议收藏」ZigBee协议栈实际上就是ZigBee协议的API接口一般步骤为:1.组网:调用协议栈的组网函数、加入网络函数,实现网络的建立与节点的加入2.发送:发送节点调用协议栈的无线数据发送函数,实现无线数据发送3.接收:接收节点调用协议栈的无线数据接收函数,实现无线数据接收大致流程:main()→osal_init_system()→osalInitTasks()→SampleAp

    2022年5月8日
    86
  • Ubuntu 12.04下SimpleScalar_PISA 的安装

    Ubuntu 12.04下SimpleScalar_PISA 的安装(1)首先准备需要的安装文件,如果没有可到以下地址下载:simpletools‐2v0.tgz:http://www.simplescalar.com/tools.htmlsimplesim‐3v0d‐with‐cheetah.tar.gz:http://www.ict.kth.se/courses/IS2202/softwaresimpleutils‐990811.tar.

    2022年6月5日
    33
  • 简述物联网,云计算,大数据和人工智能的相互关系_物联网应用领域

    简述物联网,云计算,大数据和人工智能的相互关系_物联网应用领域我们在《互联网进化论》一书中提出“互联网的未来功能和结构将于人类大脑高度相似,也将具备互联网虚拟感觉,虚拟运动,虚拟中枢,虚拟记忆神经系统”,并绘制了一幅互联网虚拟大脑结构图。根据这一观点,我们尝试分析目前互联网最流行的四个概念————-大数据,云计算,物联网和移动互联网与传统互联网之间的关系。从这幅图中我们可以看出:物联网对应了互联网的感觉和运动神…

    2022年9月27日
    4
  • Qt面试题整理

    Qt面试题整理1、Qt信号槽机制的优势(1)类型安全。需要关联的信号和槽的签名必须是等同的,即信号的参数类型和参数个数同接收该信号的槽的参数类型和参数个数相同。不过,一个槽的参数个数是可以少于信号的参数个数的,但缺少的参数必须是信号参数的最后一个或几个参数。如果信号和槽的签名不符,编译器就会报错。(2)松散耦合。信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无需知道是哪个对象的哪个槽需要接收它发出的…

    2022年6月25日
    95

发表回复

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

关注全栈程序员社区公众号