判断大小简单算法_JVM GC算法

在判断哪些内存需要回收和什么时候回收用到GC 算法,本文主要对GC 算法进行讲解。

JVM垃圾判定算法

常见的JVM垃圾判定算法包括:引用计数算法、可达性分析算法

引用计数算法(Reference Counting)

引用计数算法是通过判断对象的引用数量来决定对象是否可以被回收。

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。

优点:简单,高效,现在的objective-c用的就是这种算法。

缺点:很难处理循环引用,相互引用的两个对象则无法释放。因此目前主流的Java虚拟机都摒弃掉了这种算法

举个简单的例子,对象objA和objB都有字段instance,赋值令objA.instance=objB及objB.instance=objA,除此之外,这两个对象没有任何引用,实际上这两个对象已经不可能再被访问,但是因为互相引用,导致它们的引用计数都不为0,因此引用计数算法无法通知GC收集器回收它们。

public class ReferenceCountingGC {    public Object instance = null;    public static void main(String[] args) {        ReferenceCountingGC objA = new ReferenceCountingGC();        ReferenceCountingGC objB = new ReferenceCountingGC();        objA.instance = objB;        objB.instance = objA;        objA = null;        objB = null;        System.gc();//GC    }}

运行结果

[GC (System.gc()) [PSYoungGen: 3329K->744K(38400K)] 3329K->752K(125952K), 0.0341414 secs] [Times: user=0.00 sys=0.00, real=0.06 secs] [Full GC (System.gc()) [PSYoungGen: 744K->0K(38400K)] [ParOldGen: 8K->628K(87552K)] 752K->628K(125952K), [Metaspace: 3450K->3450K(1056768K)], 0.0060728 secs] [Times: user=0.05 sys=0.00, real=0.01 secs] Heap PSYoungGen      total 38400K, used 998K [0x00000000d5c00000, 0x00000000d8680000, 0x0000000100000000)  eden space 33280K, 3% used [0x00000000d5c00000,0x00000000d5cf9b20,0x00000000d7c80000)  from space 5120K, 0% used [0x00000000d7c80000,0x00000000d7c80000,0x00000000d8180000)  to   space 5120K, 0% used [0x00000000d8180000,0x00000000d8180000,0x00000000d8680000) ParOldGen       total 87552K, used 628K [0x0000000081400000, 0x0000000086980000, 0x00000000d5c00000)  object space 87552K, 0% used [0x0000000081400000,0x000000008149d2c8,0x0000000086980000) Metaspace       used 3469K, capacity 4496K, committed 4864K, reserved 1056768K  class space    used 381K, capacity 388K, committed 512K, reserved 1048576KProcess finished with exit code 0

从运行结果看,GC日志中包含“3329K->744K”,意味着虚拟机并没有因为这两个对象互相引用就不回收它们,说明虚拟机不是通过引用技术算法来判断对象是否存活的。

可达性分析算法(根搜索算法)

可达性分析算法是通过判断对象的引用链是否可达来决定对象是否可以被回收。

从GC Roots(每种具体实现对GC Roots有不同的定义)作为起点,向下搜索它们引用的对象,可以生成一棵引用树,树的节点视为可达对象,反之视为不可达。

9119aa616072d9d1a5dd1475f3365e2b.png

在Java语言中,可以作为GC Roots的对象包括下面几种:

•虚拟机栈(栈帧中的本地变量表)中的引用对象。•方法区中的类静态属性引用的对象。•方法区中的常量引用的对象。•本地方法栈中JNI(Native方法)的引用对象

真正标记以为对象为可回收状态至少要标记两次。

四种引用

强引用就是指在程序代码之中普遍存在的,类似"Object obj = new Object()"这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象

Object obj = new Object();

软引用是用来描述一些还有用但并非必需的对象,对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK1.2之后,提供了SoftReference类来实现软引用。

Object obj = new Object();SoftReference sf = new SoftReference(obj);

弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象,只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK1.2之后,提供了WeakReference类来实现弱引用。

Object obj = new Object();WeakReference wf = new WeakReference(obj);

虚引用也成为幽灵引用或者幻影引用,它是最弱的一中引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。在JDK1.2之后,提供给了PhantomReference类来实现虚引用。

Object obj = new Object();PhantomReference pf = new PhantomReference(obj);

JVM垃圾回收算法

常见的垃圾回收算法包括:标记-清除算法,复制算法,标记-整理算法,分代收集算法

在介绍JVM垃圾回收算法前,先介绍一个概念。

Stop-the-World

Stop-the-world意味着 JVM由于要执行GC而停止了应用程序的执行,并且这种情形会在任何一种GC算法中发生。当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态直到GC任务完成。事实上,GC优化很多时候就是指减少Stop-the-world发生的时间,从而使系统具有高吞吐 、低停顿的特点。

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

之所以说标记/清除算法是几种GC算法中最基础的算法,是因为后续的收集算法都是基于这种思路并对其不足进行改进而得到的。标记/清除算法的基本思想就跟它的名字一样,分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

标记阶段:标记的过程其实就是前面介绍的可达性分析算法的过程,遍历所有的GC Roots对象,对从GC Roots对象可达的对象都打上一个标识,一般是在对象的header中,将其记录为可达对象;

清除阶段:清除的过程是对堆内存进行遍历,如果发现某个对象没有被标记为可达对象(通过读取对象header信息),则将其回收。

不足:

•标记和清除过程效率都不高•会产生大量碎片,内存碎片过多可能导致无法给大对象分配内存。

d90451b5c8b7c8880398e58e86a4deb3.png

复制算法(Copying)

将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。

现在的商业虚拟机都采用这种收集算法来回收新生代,但是并不是将内存划分为大小相等的两块,而是分为一块较大的 Eden 空间和两块较小的 Survior 空间,每次使用 Eden 空间和其中一块 Survivor。在回收时,将 Eden 和 Survivor 中还存活着的对象一次性复制到另一块 Survivor 空间上,最后清理 Eden 和 使用过的那一块 Survivor。HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1,保证了内存的利用率达到 90 %。如果每次回收有多于 10% 的对象存活,那么一块 Survivor 空间就不够用了,此时需要依赖于老年代进行分配担保,也就是借用老年代的空间。

不足:

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

7c77102b170dace5983a2147783dec3e.png

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

标记—整理算法和标记—清除算法一样,但是标记—整理算法不是把存活对象复制到另一块内存,而是把存活对象往内存的一端移动,然后直接回收边界以外的内存,因此其不会产生内存碎片。标记—整理算法提高了内存的利用率,并且它适合在收集对象存活时间较长的老年代。

不足:

效率不高,不仅要标记存活对象,还要整理所有存活对象的引用地址,在效率上不如复制算法。

8a13629d3e10700fb05d2e8a8caf6741.png

分代收集算法(Generational Collection)

分代回收算法实际上是把复制算法和标记整理法的结合,并不是真正一个新的算法,一般分为:老年代(Old Generation)和新生代(Young Generation),老年代就是很少垃圾需要进行回收的,新生代就是有很多的内存空间需要回收,所以不同代就采用不同的回收算法,以此来达到高效的回收算法。

新生代:由于新生代产生很多临时对象,大量对象需要进行回收,所以采用复制算法是最高效的。

老年代:回收的对象很少,都是经过几次标记后都不是可回收的状态转移到老年代的,所以仅有少量对象需要回收,故采用标记清除或者标记整理算法

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

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

相关文章

stream分组计数_Java Stream:第2部分,计数始终是计数吗?

stream分组计数在上一篇有关该主题的文章中 ,我们了解到JDK 8 stream()::count需要更长的时间来执行Stream更多的元素。 对于最新的JDK(例如Java 11),简单的流管道不再是这种情况。 了解JDK本身如何进行改进。 Java 8 在上一篇文…

女生学计算机类什么专业好就业前景,2019高考:适合女生报考的10大专业!就业前景好,待遇稳定!...

如今考大学不再是单纯的提升学历,也要为自己未来的工作考虑。尤其是女生,更要考虑就业问题。因为很多专业都不太适合女生去做,甚至都不招收女生。不过也有其他的专业很适合女生,不仅就业前景好,而且很好找工作&#xf…

macOS安装Maven_IDEA集成Maven

文章目录下载 Maven安装 Maven配置环境变量关于 settings.xml 文件配置本地仓库Maven 默认的远程中央仓配置镜像仓库IntelliJ IDEA 集成 Maven下载 Maven 官方下载地址:https://maven.apache.org/download.cgi 打开官方下载页面,页面拖到下面&#xff…

bootstrap样式异常_处理异常功能样式

bootstrap样式异常Java从一开始就支持检查异常。 在Java 8中,语言元素lambda和支持流操作的RT库修改将功能编程风格引入了该语言。 函数样式和异常并不是真正的好朋友。 在本文中,我将描述一个简单的库,该库在某种程度上类似于使用Optional处…

无线鼠标可以强制配对_赛睿Rival 3 Wireless游戏鼠标评测:无限全能

近两年,外设无线技术日渐成熟,也让无线外设产品出现了爆发式增长。随着无线外设产品开始在职业赛场上崭露头角,让越来越多的用户更加青睐便利性与体验感极佳的无线外设产品。赛睿作为老牌外设厂商,在2018年就推出了采用双传感器并…

clear nTotal nNum=1计算机考试,信息学奥赛常考算法——模拟法

★模拟法有些问题的描述和解决方法已经很清楚,只需要按照描述去一步一步的执行即可,这种方法就是计算机解决问题的一种最普遍最直接的方法------模拟法。模拟法并不是程序,只是我们依赖计算机的运算速度解决问题的一种方法或模式,…

junit 测试目录_JUnit 5测试中的临时目录

junit 测试目录JUnit 4 TemporaryFolder Rule允许开发人员使用临时目录创建测试。 使用JUnit 5时,不支持Rule因此测试文件和目录需要一点点额外的工作。 幸运的是,有了JUnit 5.4,有一个新的内置扩展可以处理测试中的临时目录。 而且它非常易于…

IntelliJ IDEA内置Maven的settings.xml文件在哪里?

IDEA 内置的 Maven 没有 settings.xml 文件,如果你自己不安装 Maven,而你又想设置 Maven 的资源仓库,你要怎么做呢? 参见:https://blog.csdn.net/Li_Ya_Fei/article/details/104432073

java生成唯一有序序列号_分布式唯一 ID 之 Snowflake 算法

SegmentFault 社区专栏:全栈修仙之路作者:semlinkerNo.1Snowflake 简介1.1 什么是 SnowflakeSnowflake is a service used to generate unique IDs for objects within Twitter (Tweets, Direct Messages, Users, Collections, Lists etc.). These IDs a…

冀教版五年级计算机教学计划,冀教版五年级上册教学计划资料

现状分析:五年级两个班现有学生四十余人,基本为我校四年级直升学生.已学习了北师大版《语文》五年级上册和冀教版《语文》五年级下册.目前普遍情况是听、写的能力尚可,读和说的能力有待提高.一班学生基础知识较为扎实,但缺乏变通性,学习较为用功,但成绩不佳;二班学生…

spring缓存_有关Spring缓存性能的更多信息

spring缓存这是我们最后一篇关于Spring的缓存抽象的文章的后续文章 。 作为工程师,您可以通过了解所使用的某些工具的内部知识来获得宝贵的经验。 了解工具的行为有助于您在做出设计选择时变得更加成熟。 在本文中,我们描述了基准测试实验和结果&#x…

提交构件到Maven的远程中央仓

参见:https://central.sonatype.org/publish/publish-guide/

ctrl导致开机弹出计算机,Win7系统开机黑屏提示Press Ctrl+Alt+Del to restart如何解决...

在使用win7系统的时候,难免会遇到各种各样的问题,比如最近有雨林木风win7旗舰版系统用户反映说开机黑屏,并提示Press CtrlAltDelto restart,该怎么解决这样的问题呢,现在给大家分享一下Win7系统开机黑屏提示PressCtrlA…

rxjava背压怎样使用_使用MicroProfile应用隔板和背压

rxjava背压怎样使用我录制了一段视频,介绍如何使用MicroProfile Fault Tolerance实现隔板和背压。 隔板后面的想法是将应用程序分成几个隔离功能的执行单元。 在企业Java应用程序中,这通常意味着定义多个线程池。 向客户端施加背压会导致向客户端添加有…

单片机蜂鸣器编程音乐_基于单片机的智能鱼缸温控系统设计

曹益豪聊城大学东昌学院机电工程系山东 聊城 252000摘 要:为满足热带鱼的饲养要求,设计了一种基于AT89C52单片机的小型智能温控鱼缸系统。该系统利用DS18B20传感器检测水温,并通过测量温度与设定温度的对比控制加热装置的通断。现详细介绍了…

计算机快捷键 还原默认值,CAD默认快捷键如何恢复?教你还原CAD默认配置的方法...

小编告诉大家AutoCAD的操作命令和各种设置分为默认和自定义。 可以根据每个人的喜好进行设置。 不必完全遵循该软件的默认操作,只是因为此快捷键是可变的,所以我仍然不习惯更改我的个人操作,并且想要恢复为默认设置,我们如何还原它…

java开发指南_Java 12新功能完整指南

java开发指南六个月飞得如此之快,是时候再次仔细研究一下即将发布的新JDK版本。 让我们满足Java 12及其向开发人员介绍的功能。 自Oracle推出加速六个月的发布节奏以来已经有一段时间了,要跟上每个版本及其添加到表中的功能越来越难了。 从好的方面来看…

python语句join_Python中的join()函数的用法

函数:string.join() Python中有join()和os.path.join()两个函数,具体作用如下: join():连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串 os.path.join():将多个路径组合后返…