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

二:JVM学习垃圾收集算法以及常用的垃圾收集器

2019独角兽企业重金招聘Python工程师标准垃圾收集器与内存分配策略简介:一:垃圾收集算法1.1:简介说起垃圾收集,

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

垃圾收集器与内存分配策略简介:

一:垃圾收集算法

1.1:简介

    说起垃圾收集,大部分人都把这项技术当做java语言的伴生物,其实,GC的历史比java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言,档Lisp在胚胎的时候,人们就在考虑GC需要完成的三件事情:

    1:那些内存需要回收

    2:什么时候回收

    3:如何回收

1.2:垃圾收集算法:

    由于笔者也是刚开始学习,对算法的具体实现不甚了解,所以请见谅。

    1.2.1标记-清除算法

        该算法也是最基础的收集算法,就给名字一样,分为标记和清除两部分,首先标记处所有需要清理的对象,然后在标记完成之后在统一回收。该算法的最大缺点就是标记清除之后会产生大量不连续的内存碎片,空间碎片化太高可能会导致,当程序在以后的运行霍城中需要分配大对象的时候没有办法找到连续的空间再去触发一次垃圾回收动作,有点得不偿失,还有一点就是该算法的收集效率也不是太高。如下所示:

20150855_HD1p.png

1.2.2:复制算法:

     为了解决效率问题,一种称为“复制”算法的收集算法出现了,他讲容量划分为大小相等的两块,每次只是用一块,当一块内存块用完之后,就把存活的对象复制到另一块上去,然后把已经使用过的内存空间一次清理掉,这样使得每次都对其中一块进行垃圾回收,再次进行内存分配的时候也不用考虑空间碎片化的问题。这种算法也有坏处就是内存压缩为原来的一半,利用率比较低,典型的空间换时间的解决方案。复制算法的执行过程如下图哦所示:

20150856_bBPN.png

而且还有一点就是复制存活对象的时候,必须要存活对象比较少,如果存活对象比较多,那么复制耗费的资源也是比较多的,IBM的研究机构表明,新生代的对象基本都是朝生夕死的,所以并不需要按照1:1的比例划分,而是将新生代内存划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和一块Survivor空间,回收的时候,将他们中的存活对象复制到另外一块没有用到的Survivor空间中,然后清理Eden和一块Survivor空间。但是也有例外,档Survivor空间不足的时候,需要依赖其他内存(这里指的是老年代)进行分配担保。

1.2.3:标记-整理算法:

    复制算法在存活率比较低的时候还好,当对象的存活率比较高的时候,比如在老年代,存活率比较高,对象的复制耗费的资源比较多的情况下就有点得不偿失,所以老年代一般不采用该算法。

    根据老年代的特点,有人提出了另外一种“标记-整理”算法,顾名思义就是先标记在整理,标记过程和“标记-清除“算法中的标记一样,但是后续步骤不是直接对可回收对象进行清理,而是让所有的存活对象都向一端移动,然后清理掉边界以外的内存,这样也避免了内存空间碎片化,过程如下图所示:

20150856_M3wa.png

1.2.4:分代收集算法:

    当前的商业虚拟机都采用的是”分代收集“算法,一般是把java堆分成新生代和老生代,这样就可以根据各个年代的特点采用最适当的垃圾收集算法,新生代中,对象大多是”朝生夕死“可以采用复制算法,而老年代的对象存活率比较高,而且没有担保空间进行内存分配,就要采用”标记-清除算法“或者”标记-整理“算法。

1.3:垃圾收集器:

    如果说垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。

目前HotSpot虚拟机的垃圾收集器主要如下:

20150856_bMmR.jpg

sun公司主要是针对新生代和老年代不同特征,采用分代收集算法,其中上图有连线的是说明可以相互搭配使用,

1.3.1:Serial收集器:

    他是最基本,历史悠久的垃圾收集器,从名字可以看得出,他是一个单线程的收集器,他的单线程不仅仅是说明她只会使用一个CPU或一条收集线程去完成垃圾回收工作,而是他在进行垃圾回收的时候,必须暂停其他所有的工作线程,简称(Stop The World)直到收集结束,可能说既然这样,那么为什么还要改收集器,俗话说:有利必有弊,他有着优于其他收集器的地方,简单而高效(相对于其他单线程收集器),对于限定单个CPU的坏境来说,Serial收集器由于没有线程交互的开销,专心做垃圾回收自然可以获得最高的单线程垃圾回收效率。

1.3.2:ParNew收集器:

    他其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数,收集算法、回收策略都与Serial收集器完全一样。

    ParNew收集器除了多线程收集之外,其他与Serial收集器相比没有太多创新之外,但是他确实运行在Server模式下的虚拟机中首选的新生代收集器,还有一个与性能无关但很重要的原因就是,除了Serial收集器外,目前只有它能与CMS收集器配合工作。CMS收集器是HotSpot虚拟机中第一款真正意义上的并发收集器,但是CMS作为老年代的收集器,却无法与jdk1.4.0中已经存在的新生代收集器Parallel Scavenge配合工作,所以在jdk1.5中使用CMS来收集老年代的时候,新生代只能选择ParNew或者Serial收集器中而一个。ParNew收集器也是使用-XX:+UseConcMarkSweepGC选项后的默认新生代收集器,也可以使用-XX:+UseParNewGC选项强制指定它。

    ParNew收集器在单CPU的环境中绝对不会比Serial收集器更好的结果。

1.3.3:Parallel Scavenge收集器

    该收集器也是一个新生代的垃圾收集器,他也是使用复制算法的收集器,又是一个并行的垃圾收集器。该收集器的特点是他的关注点与其他的收集器不同,CMS等收集器的关注点是尽可能缩短垃圾回收时用户线程的停顿时间,而parallel Scavenge收集器的目标是大道一个可控制的吞吐量。所谓吞吐量就是CPU用于运行用于代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾回收时间),比如虚拟机总共运行100分钟,垃圾回收占用了1分钟,那么吞吐量就是99%。

    该收集器提供了两个参数精确控制吞吐量,一个是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis,在一个就是直接设置吞吐量大小的-XX:GCTimeRatio参数。

1.3.4:Serial Old收集器

    他是Serial收集器的老年代版本,同样是一个单线程收集器,它采用的是“标记-整理”算法,在client模式下采用,该收集器的主要意义就是第一是在jdk1.5及以前版本中与Parallel Scavenge收集器搭配使用,第二就是作为CMS收集器的备用方案。

1.3.5:Parallel Old收集器

    他是Parallel Scavenge收集器的老年代版本,采用的是多线程和”标记-整理“算法,该收集器是jdk1.6之后提供的,在此之前,新生代的Parallel Scavenge收集器一直处于比较尴尬的状态,原因是,如果新生代选择了Parallel Scavenge收集器,老年代除了Serial Old收集器之外别无选择,但是Serial Old收集器运行在服务端应用新能上的拖累,即时使用了Parallel Scavenge收集器也未必能在整理应用上获得吞吐量最大化的效果,又因为老年代的Serial Old收集器无法应用多CPU的处理能力,在老年代很大而且硬件比较高级的环境中,这种组合的吞吐量甚至还不一定有Parnew加CMS组合给力。

    知道Parallel Old收集器出现之后,”吞吐量优先“收集器终于有了名副其实的应用组合,在注重吞吐量机CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加上Parallel Old收集器。

1.3.6:CMS收集器:

    CMS(Concurrent Mark Sweep)收集器是一种获取最短回收停顿时间为目标的收集器,目前很大一部分的java应用都集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,已给应用带来较好的体验,CMS收集器就非常符合这类应用的需求。

    从名字上看就可以看出CMS收集器采用的是”标记-清楚“算法,他的运行过程向对于前面的集中收集器来说更复杂一些,主要分为四个步骤:

    1:初始标记,2:并发标记,3:重新标记,4:并发清除,其中初始标记和并发标记仍然需要“Stop The World”,初始标记只是标记GC Roots能直接关联到的对象,速度很快,并发表及阶段就是进行GC Roots Tracing的过程,而重新标记是为了修正并发并发标记期间,因用户程序继续运行而导致标记产生变动的一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍微长一些,但远比并发标记的时间段。

    CMS是一款很优秀的收集器,他的主要优点是并发收集、低停顿,但是他还有很多缺点

    1:对CPU资源比较敏感,2:无法处理浮动垃圾,3:就是CMS是一款基于”标记-清楚“算法,他会产生一些不连续的空间碎片,但是CMS还提供了一个-XX:UseCMSCompactAtFullCollection的参数,用于在享受完Full GC服务只有额外享受一次免费的碎片整理过程,但是内存整理的过程是无法并发的,空间碎片问题没有了,但是停顿时间变长了,虚拟机设计团队还提供了一个额外的参数-XX:CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC会后,跟着来一次带压缩的。

1.3.7:G1收集器

    G1收集器是垃圾收集器理论进一步发展的产物,他与前面CMS收集器相比有着明显的改进,一是G1收集器是基于”标记-整理“算法实现的收集器,也就是说他不会产生空间碎片,这对长时间运行的系统来说很重要。二是他可以非常精确的控制停顿,他们让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集的时间不超过N毫秒。

    G1收集器可以实现在基本补习生吞吐量的前提下完成低停顿的内存回收,这是由于它能够极力避免全区域的内存垃圾收集,之前的垃圾收集器进行的收集都是整个新生代或老年代,而G1是将整个java堆划分为多个大小固定的独立区域,并且跟踪这些区域里面的垃圾堆积成都,在后台维护一个优先列表,每次根据允许的垃圾收集时间,优先回收垃圾最多的区域,这也是G1名字的来历,Garbage First,区域划分及优先级的区域回收,保证了G1收集器在优先的时间内可以获得最高的垃圾效率。

1.4:垃圾回收器参数:

    UseSerialGC:虚拟机运行在Client模式下的默认值,打开次开关后,使用Serial+Serial Old收集器组合进行内存垃圾回收

    UseParNewGC:打开此开关后,使用ParNew+Serial Old收集器进行垃圾回收

    UseConMarkSweepGC:打开此开关后,使用ParNew +CMS + Serial Old收集器组合进行内存回收,Serial Old收集器将作为CMS收集器出现在Concurrent ModeFailure失败后的后备收集器使用

    UseParallelGC:虚拟机运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge+Servial Old收集器进行垃圾回收

    UseParallelOldGC:打开此开关后,虚拟机采用Parallel Scavenge + Parallel Old收集器进行垃圾收集

    SurvivorRatio:新生代中Eden区域与Survivor区域的容量值比,一般是8,代表的比例关系为8:1

    PretenureSizeThreshold:直接晋升老年代对象的大小,设置这个参数后,对象大于该参数的直接进入老年代

    MaxTenuringThreshold:晋升老年代的对象年龄,每个对象在坚持过一次MinorGC之后,年龄加1,超过这个参数直接进入老年代

    UseAdaptiveSizePolicy:动态调整java堆中各个区域的大小以及进入老年代的年龄

    HandlePromotingFailure:是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden和Survivor区的所有对象都存活的极端情况

    ParallelGCThreads:设置并行GC时内存回收的线程数量

    GCTimeRation:GC时间中总时间的比例,默认值为99,即允许1%的GC时间,尽在Parallel Scavenge收集器时生效

    MaxGCPauseMills:设置GC的最大停顿时间,尽在使用Parallel Scavenge收集器时生效

    CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发垃圾收集,默认值为68%,当且仅在使用CMS收集器时生效

    UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否进行一次内存碎片整理,当且仅在使用CMS收集器时生效

    CMSFullGCsBeforeCompaction:设置CMS收集器在进行若干次垃圾收集后自动启用一次碎片整理,当且仅在使用CMS收集器时生效。


转:https://my.oschina.net/u/1034481/blog/617980



推荐阅读
  • Python处理Word文档的高效技巧
    本文详细介绍了如何使用Python处理Word文档,涵盖从基础操作到高级功能的各种技巧。我们将探讨如何生成文档、定义样式、提取表格数据以及处理超链接和图片等内容。 ... [详细]
  • 非公版RTX 3080显卡的革新与亮点
    本文深入探讨了图形显卡的进化历程,重点介绍了非公版RTX 3080显卡的技术特点和创新设计。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • CentOS7源码编译安装MySQL5.6
    2019独角兽企业重金招聘Python工程师标准一、先在cmake官网下个最新的cmake源码包cmake官网:https:www.cmake.org如此时最新 ... [详细]
  • 本文详细介绍了如何使用Python编写爬虫程序,从豆瓣电影Top250页面抓取电影信息。文章涵盖了从基础的网页请求到处理反爬虫机制,再到多页数据抓取的全过程,并提供了完整的代码示例。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 深入解析:手把手教你构建决策树算法
    本文详细介绍了机器学习中广泛应用的决策树算法,通过天气数据集的实例演示了ID3和CART算法的手动推导过程。文章长度约2000字,建议阅读时间5分钟。 ... [详细]
  • 离线环境下的Python及其第三方库安装指南
    在项目开发中,有时会遇到电脑只能连接内网或完全无法联网的情况。本文将详细介绍如何在这种环境下安装Python及其所需的第三方库,确保开发工作的顺利进行。 ... [详细]
  • 掌握远程执行Linux脚本和命令的技巧
    本文将详细介绍如何利用Python的Paramiko库实现远程执行Linux脚本和命令,帮助读者快速掌握这一实用技能。通过具体的示例和详尽的解释,让初学者也能轻松上手。 ... [详细]
  • 自学编程与计算机专业背景者的差异分析
    本文探讨了自学编程者和计算机专业毕业生在技能、知识结构及职业发展上的不同之处,结合实际案例分析两者的优势与劣势。 ... [详细]
  • 使用Python在SAE上开发新浪微博应用的初步探索
    最近重新审视了新浪云平台(SAE)提供的服务,发现其已支持Python开发。本文将详细介绍如何利用Django框架构建一个简单的新浪微博应用,并分享开发过程中的关键步骤。 ... [详细]
  • 最近团队在部署DLP,作为一个技术人员对于黑盒看不到的地方还是充满了好奇心。多次咨询乙方人员DLP的算法原理是什么,他们都以商业秘密为由避而不谈,不得已只能自己查资料学习,于是有了下面的浅见。身为甲方,虽然不需要开发DLP产品,但是也有必要弄明白DLP基本的原理。俗话说工欲善其事必先利其器,只有在懂这个工具的原理之后才能更加灵活地使用这个工具,即使出现意外情况也能快速排错,越接近底层,越接近真相。根据DLP的实际用途,本文将DLP检测分为2部分,泄露关键字检测和近似重复文档检测。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
author-avatar
黄石幽兰it
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有