热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java虚拟机之垃圾回收概念与算法

一:垃圾回收概念GC中的垃圾:指的是,存在于内存中的不会再被使用的对象。为什么要进行垃圾回收:如果不及时对内存中的垃圾进行清理,那么,这些垃圾对象所占用的内存空间会一直保留到应用程序结束

一:垃圾回收概念
GC中的垃圾:指的是,存在于内存中的不会再被使用的对象。
为什么要进行垃圾回收:如果不及时对内存中的垃圾进行清理,那么,这些垃圾对象所占用的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用。如果大量不会被使用的对象一直占用内存空间不放,需要内存空间时,就无法使用这些被垃圾对象占用的内存,从而有可能导致内存溢出。因此,堆内存空间的管理来说,识别和清理垃圾对象是至关重要的。
在早期的c、c++,垃圾回收基本上是手工进行清理,现在java,c#,python等语言都是用了垃圾回收的思想。开发人员只需要关注内存的申请,而内存的释放可以由系统自动识别和完成。

二:讨论常用的垃圾回收算法
常用算法:引用计数法,标记清除法,复制算法,标记压缩法,分代算法和分区算法。
1:引用计数法:是最经典也是最古老的一种垃圾收集方法,在微软的COM组件计数,Adobe的ActionScript3中,都可以找到引用计数器的身影。引用计数器的实现很简单,对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失败时,引用计数器就减1。只要对象A的引用计数器的值为0,则对象A就不可能再被使用。
实现也非常简单,只需要为每个对象配备一个整型的计数器即可,但是,引用计数器有两个非常严重的问题

→无法处理循环引用的情况 ,因此,在java的垃圾回收器中,没有使用这种算法 (循环问题简述如下:有对象A和对象B,对象A中含有对象B的引用,对象B中含有对象A的引用。此时对象A和B的引用计数器都不为0。但是,在在系统中,却不存在任何第三个对象引用了A或者B,也就是说,A和B是应该被回收的垃圾对象,但由于垃圾对象间的相互引用,从而使垃圾回收器无法识别,引起内存泄漏。)

→ 引用计数器要求在每次因引用产生和消除的时候,需要伴随一个加法操作和减法操作,对系统性能会有一定得影响。

2:标记清除法:标记清除算法是现代垃圾回收算法的思想基础。标记清楚算法将垃圾回收分为两个阶段:标记阶段和清除阶段,说白了就是对不是垃圾对象做标记,之后清除未
被标记的对象。

标记清除法的缺点:会造成内存空间的不连续性。在对象的堆空间分配过程中,尤其是大对象的内存分配,不连续内存空间的工作效率要远低于连续的内存空间。

3:复制算法:复制算法的核心思想:将原有的内存空间分为两块,每次只是用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,
清除正在使用的内存块中的所有对象,交换两个内存的角色(交换后的对象,存储空间是连续的),完成垃圾回收。

复制算法的适用场景:垃圾对象较多的区域,垃圾对象的回收的效率相对较高(因为复制的对象相对较少)。因为垃圾对象较少的话,复制的对象也就较多,垃圾回收的效率
相对较低

复制算法的缺点:将系统内存折半。

在java的新生代串行垃圾回收器中,使用了复制算法的思想。(这里补充下堆的空间结构:堆的空间结构由 新生代和老年代组成。新生代包括 eden 区、from区和 to区,老年代
包括tenured区)新生代分为eden空间,form空间和to空间。其中from 和to空间可以被视为用于复制的两块大小相同、地位相等、且可进行角色互换的空间块。from 和to空间也成为
survivor(幸存者)空间,用于存放未被回收的对象。

新生代:存放年轻对象的堆空间。年轻对象指刚刚创建的,或者经历垃圾回收次数不多的对象。
老年代:存放老年对象的堆空间。老年对象指经历过多次垃圾回收依然存活的对象。

在垃圾回收时,eden空间中的存活对象会被复制到未使用的幸存者空间(假设是to),正在使用的survivor空间(假设是from)中的年轻对象也会被复制到to空间中(大对象,或者老年对象会直接进入老年代,如果to空间已满,则对象也会直接进入老年代)。此时,eden空间和from空间中剩余对象就是垃圾对象,可以直接清除,to空间则存放此次回收后的存活对象。这种改进的复制算法,既保证了空间的连续性,又避免了大量的内存空间浪费。

4:标记压缩法:标记压缩法是一种老年代的回收算法,它在标记清除法的基础上做了一些优化。标记压缩法并不只是简单地清理未标记的对象,而是将所有的存活对象压缩到内
存的一端(压缩的对象是连续的排列在内存空间中),之后清理标记边间外所有的空间,这种方法既避免了内存空间的不连续性,又不需要折半内存,因此性价比高。

5:分代算法:说白了就时根据垃圾回收对象的特性,使用合适的算法回收。这里的分代指的是新生代和老年代,新生代存活的对象相对较少可以用复制算法,老年代存活的对
相对较多,可以使用标记压缩算法回收。

对于新生代和老年代来说,通常,新生代回收的频率很高,但是每次回收的耗时都很短,而老年代回收的频率比较低,但是会消耗更多的时间,为了支持高频率的新生代回收,
虚拟机可能使用一种叫做卡表的数据结构,卡表为一个比特位集合,每一个比特位可以用来表示老年代的某一区域中的所有对象是否持有新生代对象的引用。这样在新生代gc时,
可以不用花大量时间扫描所有老年代对象,来确定每一个对象的引用关系,而可以先扫描卡表,只有当卡表的标记位为1时,才需要扫描给定区域的老年代对象,而卡表位为0的
所在区域的老年代对象,一定不会含有新生代对象的引用。

6:分区算法:分代算将对象的生命周期长短划分为两个部分,分区算法将整个堆空间划分成连续的不同小区间,每一个小区间都独立使用,独立回收。这种算法的好处是可以
控制一次回收多少个小区间。

一般来说,在相同条件下,堆空间越大,一次gc时所需要的时间就越长,从而产生的停顿也越长。为了更好的控制gc产生的停顿时间,将一块大的内存区域分割成多个小块,
根据目标的停顿时间,每次合理的回收若干个小区间,而不是整个堆空间,从而减少一次gc所产生的停顿

总结 掌握 gc每个算法的优缺点,适用场景。理解记忆。
文章内容如有错误 欢迎加 QQ :82479297 探讨


推荐阅读
  • JavaScript简介及语言特点
    本文介绍了JavaScript的起源和发展历程,以及其在前端验证和服务器端开发中的应用。同时,还介绍了ECMAScript标准、DOM对象和BOM对象的作用及特点。最后,对JavaScript作为解释型语言和编译型语言的区别进行了说明。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 开发笔记:Python之路第一篇:初识Python
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Python之路第一篇:初识Python相关的知识,希望对你有一定的参考价值。Python简介& ... [详细]
  • 无损压缩算法专题——LZSS算法实现
    本文介绍了基于无损压缩算法专题的LZSS算法实现。通过Python和C两种语言的代码实现了对任意文件的压缩和解压功能。详细介绍了LZSS算法的原理和实现过程,以及代码中的注释。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • 2018深入java目标计划及学习内容
    本文介绍了作者在2018年的深入java目标计划,包括学习计划和工作中要用到的内容。作者计划学习的内容包括kafka、zookeeper、hbase、hdoop、spark、elasticsearch、solr、spring cloud、mysql、mybatis等。其中,作者对jvm的学习有一定了解,并计划通读《jvm》一书。此外,作者还提到了《HotSpot实战》和《高性能MySQL》等书籍。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 【Java面试】简单说一下你对序列化和反序列化的理解
    Hi,大家好,我是Mic一个工作4年的粉丝,投了很多简历好不容易接到一个互联网公司的面试邀约。在面试第一轮就被干掉了,原因是对主流互联网技术理解太浅了。其中就有一个这样的问题:“简 ... [详细]
  • 生产环境下JVM调优参数的设置实例
     正文前先来一波福利推荐: 福利一:百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。福利二 ... [详细]
  • 一面自我介绍对象相等的判断,equals方法实现。可以简单描述挫折,并说明自己如何克服,最终有哪些收获。职业规划表明自己决心,首先自己不准备继续求学了,必须招工作了。希望去哪 ... [详细]
  • 微信公众号:内核小王子关注可了解更多关于数据库,JVM内核相关的知识;如果你有任何疑问也可以加我pigpdong[^1]jvm一行代码是怎么运行的首先,java代码会被编译成字 ... [详细]
author-avatar
嗷唔喵_105
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有