jvm常见的垃圾回收算法_垃圾回收机制算法

jvm常见的垃圾回收算法_垃圾回收机制算法在早期的计算机语言,比如C和C++,需要开发者手动的来跟踪内存,这种机制的优点是。但是它也有它的缺点,新的编程语言,比如JAVA,Go,Python,PHP…现在市面上的大部分主流编程语言,都采取了一个方案,那就是“垃圾回收机制”,运行时自身会运行相应的垃圾回收机制。。垃圾回收器(GC)会在适当的时候将的内存给释放掉。GC的优点:GC的缺点:JVM的内存结构包括四大区域:1.程序计数器2.栈(虚拟机栈,本地方法栈)3.堆4.方法区举个例子,任何组织里,人都有三个派别,1.积极派2.消极派

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

Jetbrains全系列IDE稳定放心使用


1. 什么是垃圾回收机制(GC)

在早期的计算机语言,比如 C 和 C++,需要开发者手动的来跟踪内存,这种机制的优点内存分配和释放的效率很高。但是它也有它的缺点如果程序员不小心忘记释放内存,从而造成内存的泄露

内存泄露:申请内存之后,忘记释放了 导致 可用的内容越来越少,最终无内存可用

新的编程语言,比如 JAVA,Go,Python,PHP… 现在市面上的大部分主流编程语言,都采取了一个方案,那就是 “垃圾回收机制”,运行时自身会运行相应的垃圾回收机制。程序员只需要申请内存,而不需要关注内存的释放垃圾回收器(GC)会在适当的时候将已经终止生命周期的变量的内存给释放掉。

1.1 垃圾回收机制的优缺点

GC的优点:

  • 它大大简化了应用层开发的复杂度(不需要开发者再去手动跟踪内存)
  • 降低了内存泄露的风险

GC的缺点:

  • 消耗额外的开销(消耗的资源更多了)
  • 会影响程序的流畅运行

2. 哪些内存需要回收

JVM的内存结构包括四大区域:1.程序计数器 2.栈 (虚拟机栈,本地方法栈)3.堆 4.方法区

在这里插入图片描述

举个例子,任何组织里,人都有三个派别,1.积极派 2.消极派 3.中间摇摆派,如图,对于上述三个派别,哪些是要进行回收释放内存的?

正在使用的内存中的对象 代表 积极派

不再使用,但是尚未回收的内存中的对象 代表消极派

中单部分为中间摇摆派
在这里插入图片描述
需要进行回收释放资源的:消极派

为什么中间摇摆派不回收释放内存呢?对于这种部分仍在使用,一部分不在使用的对象,整体来说是不释放的!等到这个对象彻底完全不使用,才真正的释放!!

注意

垃圾回收的基本单位是“对象”,而不是“字节”

3. 垃圾回收具体是如何回收的

分为两个阶段:

  1. 找垃圾/判定垃圾
  2. 回收垃圾(释放内存)

3.1 找垃圾/判定垃圾

如何找 垃圾/判定垃圾呢?当下主流的思路,有两种方案:

  1. 基于引用计数(不是Java中采取的方案,这是别的语言,像Python采取的方案)
  2. 基于可达性分析(这个是Java采取的方案)

3.11 基于引用计数

什么是基于引用计数:简单来说,针对每个对象,都会额外引入一小块内存,保存这个对象有多少个引用指向他
举个例子
1.Test t = new Test();,此时 new 了一个对象,那么我们就会额外引入一小块内存,此时 t 指向这个对象的引用,因此 引用计数 加 1

在这里插入图片描述
2.Test t2 = t; 此时 t 和 t2 都是指向这个对象的引用,此时引用计数 从1 变为 2
在这里插入图片描述
3.

void func() {
   Test t = new Test();
   Test t2 = t;
}

func()//调用方法过程中,创建了对象(分配内存),在方法执行过程中,引入计数量是2,当方法执行结束,由于 t 和 t2 都是局部变量,跟着栈帧一起释放了,这一释放就导致引用计数为0了(没有引用指向这个对象了,也就没有代码能够访问到这个对象了),此时就认为这个对象是个垃圾!

注意:引用计数为0的时候,就不再使用了,这个内存不再使用,就释放了(为后面理解做铺垫)

3.12 引用计数的优缺

引用技术,简单可靠高效,但是有个两个致命缺陷!!

  1. 空间利用率比较低,每个 new 的对象都得搭配个 计数器,计数器假设 4个字节,如果对象本身很大(几百个字节),多出来4个字节,就不算什么,但是如果本身对象很小(自己才4个字节),多出4个字节,相当于空间被浪费了一半
  2. 会有循环引用的问题

循环引用问题:写个代码举例子便于理解

// 先创建一个类
class Test {
// 成员变量
    Test t = null;
}
// 创建实例
Test t1 = new Test();
Test t2 = new Test();

画出内存布局:

在这里插入图片描述

t1.t = t2;//把 t2 赋值给了 t1里面的t属性,此时对象2有两个引用
引用计数加1,变为2

在这里插入图片描述

t2.t = t1// 把 t1 赋值给 t2 里面的 t 属性,此时对象1 有两个引用
引用计数加1,变为2

在这里插入图片描述
接下来,烧脑的环节:

t1 = null
t2 = null

在这里插入图片描述

此时此刻,两个对象的引用计数,不为0,所以无法释放,但是由于引用长在彼此的身上,外界的代码也无法访问到这两个对象,此时此刻,这俩对象,就不能使用,又不能释放,就出现了“内存泄露”的问题。

所以,像 Python,PHP里进行GC也不只靠引用计数,还依赖其他的机制配合,但是Java可以直接采用可达性分析,来判断垃圾

3.13 基于可达性分析

基于可达性分析:简单的来说,通过额外的线程,定期的针对整个内存空间的对象进行扫描,有一些起始位置(称为 GCRoots),会类似于 深度优先遍历一样,把可以访问到的对象都标记一遍(带有标记的对象就是可达对象),没有被标记的对象,就是不可达,也就是垃圾!

什么才算 GCRoots

  1. 栈上的局部变量
  2. 常量池中的引用指向的对象
  3. 方法区中的静态成员指向的对象

举个栗子吧,比如:写个代码,构造一个二叉树
在这里插入图片描述
如果我们在外面的代码中

Node root = a

代码中只要拿到 树 根节点,就可以掌握所有的节点,树上的任意节点,都可以通过 a 直接/间接的获取到

换句话说,GC在进行可达性分析的时候,当 GC 扫描到 a 的时候,就会把 a 能访问到的所有元素都去访问一遍,并且进行标记,所标记的节点 表示 都不是 垃圾

如果代码中,写了如下代码

c.right = null

在这里插入图片描述
则此时意味着,从 a 出发,访问不到 f,f 就是 不可达,f 就是垃圾,f 就应该被回收

如果代码中

a.right = null

在这里插入图片描述
此时从 a 出发,c 和 f 都是不可达了,也就都被标记成垃圾了!

从上面的这几点我们可以看出,可达性分析是去遍历每一个对象,如果内存中的对象特别多,这个遍历就会很慢,因此 GC 还是比较消耗时间和系统资源的!

3.14 可达性分析的优缺点

优点:

  • 克服了引用计数的两个缺点:
    1. 空间利用率低
    2. 循环引用

缺点:

  • 系统开销大,遍历一次可能比较慢

tips:

找垃圾,核心就是确认这个对象未来是否还会使用,什么算不使用了?没有引用,就不使用了

明确了谁是垃圾之后,接下来就要回收垃圾了!

3.2 回收垃圾(释放内存)

3.21 回收垃圾(释放内存)三种基本策略

标记 – 清除

如图:这是一块内存,上面被分成了很多小块,其中有些部分是垃圾(打钩的)

在这里插入图片描述

这里的 标记 ,就是可达性分析的过程

清除,就是直接释放内存 ,灰色区域代表释放内存

在这里插入图片描述

此时如果直接释放,虽然内存还是还给了系统,但是被释放的内存是离散的(不是连续的)

分散开带来的问题就是:“内存碎片”,这个问题其实非常影响程序的执行!

内存碎片:比如,空闲的内存,有很多,假设一共是 1G,如果要申请 500M 内存,也是可能申请失败的,因为要申请 500M 的内存 必须是连续的,每次申请,都是申请的连续的内存空间,而这里的 1G 可能是多个 碎片加在一起 才 1G,可用的并不多

为了解决内存碎片因此我们引入了复制算法!

复制算法

如图:一块内存,分成两半,左边一半有很多对象,打钩的标记为垃圾,右边为 左边不是垃圾的,拷贝过来

在这里插入图片描述

然后再将左边全部标记为垃圾(灰色),全部释放掉,我们就能保证,左右两侧空间都是整体连续的

在这里插入图片描述

此时内存碎片问题就迎刃而解了!

注意:复制算法的问题有如下几点

  • 内存空间利用率低(只能用一般的空间)
  • 如果要保留的的对象多,要释放的对象少,此时复制开销就很大

针对复制算法我们进行改进!–》 标记 – 整理

标记 – 整理

如图:还是一块内存,上面有一些对象,其中一些被标记为垃圾(打钩的)

在这里插入图片描述

如何进行标记 – 整理呢?

类似于顺序表删除中间元素,有一个搬运操作,我们将 3 搬运到 2 ,再将 5 搬运到 3 ,再把 7 搬运到 4 然后再把后面的部分整体的释放掉

在这里插入图片描述

这个方案空间利用率是高了,但是仍然没有解决复制/搬运元素开销大的问题~

3.22 分代回收

上述的三个方案,虽然能解决回收垃圾的问题,但是都有缺陷,实际 JVM 中的实现,会把多种方案结合起来一起使用,这个思路我们称为 “分代回收”

在这里插入图片描述

我们这个对象,他是怎样在这个区域里来回 轮转 的呢?

  1. 刚创建出来的对象,就放在伊甸区
  2. 如果伊甸区的对象熬过一轮 GC 扫描,就会被拷贝到 幸存区(伊甸区 到 幸存区 应用了复制算法)
  3. 在后续的几轮 GC 中,幸存区的对象就在两个幸存区之间来回拷贝(复制算法),每一轮都会淘汰一波幸存者
  4. 在持续若干轮之后,对象终于,进入老年代,老年代有个特点,里面的对象都是比较老的(年级大的),因此老年代的 GC 扫描频率大大低于新生代。老年代中使用标记整理的方式进行回收!

上述过程是面试中的经典问题!!!一定要重点掌握啊!

注意:
在这里插入图片描述

注意!!!
分代回收中,还有一个特殊情况,有一类对象可以直接进入老年代(大对象,占有内存多的对象),大对象拷贝开销比较大,不适合使用复制算法!

4. 垃圾回收器

上面说的找垃圾,和释放垃圾,说的都是算法思想,不是具体落地实现,在JVM里,真正实现上述算法的模块称为“垃圾回收器”

在这里插入图片描述

在这里插入图片描述


?✨总结

“种一颗树最好的是十年前,其次就是现在”

所以,

“让我们一起努力吧,去奔赴更高更远的山海”

如果有错误❌,欢迎指正哟?

?如果觉得收获满满,可以动动小手,点点赞?,支持一下哟?

以梦为马,不负韶华

在这里插入图片描述

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

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/182489.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Java:JavaSocket编程开发多人聊天室「建议收藏」

    Java:JavaSocket编程开发多人聊天室「建议收藏」Java|JavaSocket编程开发多人聊天室实现内容运行结果部分代码完整代码实现内容用Java图形用户界面编写聊天室服务器端和客户端,支持多个客户端连接到一个服务器。每个客户端能够输入账号。可以实现群聊(聊天记录显示在所有客户端界面)。完成好友列表在各个客户端上显示。可以实现私人聊天,用户可以选择某个其他用户,单独发送信息。服务器能够群发系统消息,能够强行让某些用户下线。客户端的上线下线要求能够在其他客户端上面实时刷新。运行结果部分代码importjava.awt

  • 英伟达官网怎么找老版本的显卡驱动

    英伟达官网怎么找老版本的显卡驱动本文分享一下贫穷博主小白苦苦寻求老驱动版本的方法。本文目录1.打开链接2.之后打开浏览器控制台3.然后在当前页面,再次点击开始搜索4.提高下载速度1.打开链接http://www.geforce.cn/drivers/beta-legacy.选择与自己的电脑显卡匹配的配置,点击开始搜索,默认结果只会出现目前最新的10个该显卡的驱动程序版本。但是我们需要较遥远老版本的显卡驱动,10个显然不够。2.之后打开浏览器控制台笔者的是谷歌浏览器,快捷键F12打开控制台,其它浏览器类似。在控制台输入如下

  • 《前端运维》一、Linux基础–09常用软件安装

    一、软件包管理RPM是RedHatPackageManager(RedHat软件包管理工具)类似Windows里面的"添加/删除程序"。软件包有几种类型,我们一起来看下:源

  • httprunner(3)用脚手架快速搭建项目[通俗易懂]

    httprunner(3)用脚手架快速搭建项目[通俗易懂]前言如何快速搭建一个httprunner项目呢?我们可以使用脚手架,脚手架就是自动地创建一些目录,形成一个项目的架构,不需要我们再手动的去创建查看创建新项目的命令先来查看一下帮助命令httpr

  • 代理重加密算法_凯撒密码采用三重加密技术

    代理重加密算法_凯撒密码采用三重加密技术1、研究背景作用:密文云数据动态共享基于用户数据隐私性考虑,用户存放在云端的数据都是加密形式存在的。而云环境中存在着大量数据共享的场景。由于数据拥有者对云服务提供商并不完全信任,不能将解密密文的密钥发送给云端,由云端来解密并分享出去。数据拥有者自己下载密文解密后,再用数据接收方的公钥加密并分享,无疑给数据拥有者带来很大的麻烦,同时也失去了云端数据共享的意义。代理重加密可以在不泄漏数据拥…

  • 手机设置分辨率命令提示_手机自定义分辨率

    手机设置分辨率命令提示_手机自定义分辨率分辨率设置命令adb shell wm size 480X480adb shell wm density240分辨率恢复命令。adb shell wm size resetadb shell wm density reset

发表回复

您的电子邮箱地址不会被公开。

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