实用垃圾收集,第1部分–简介

这是我打算写的一系列博客文章的第一部分,其目的是解释垃圾回收在现实世界中的工作方式(特别是在JVM中 )。 我将介绍一些我认为对于充分理解垃圾收集对于实际目的是必要的理论,但是将其降至最低。

其动机是在各种情况下(例如在Cassandra邮件列表中)不断出现与垃圾回收相关的问题。 尝试提供帮助时的问题是,在针对特定情况定制的邮件列表回复中临时解释垃圾收集的细微差别是一项过多的工作,而您几乎没有关于这种情况的足够信息来告诉某人他们的情况特殊问题是由引起的。

我希望本指南将成为我回答这些问题的参考。 我希望它会足够详细,以便有用,但易于消化,并且对于广泛的读者来说也不够学术性。
我非常感谢您对我需要澄清,改进,彻底淘汰等方面的任何反馈。
这里的许多信息并非特定于Java。 但是,为了避免不断调用通用和抽象术语,我将在可能的地方用Hotspot JVM的具体术语进行发言。

为什么有人要关心垃圾收集器?

这是一个好问题。 完美的垃圾收集器可以在没有人注意到它存在的情况下完成其工作。 不幸的是,没有已知的完美的垃圾回收算法。 此外,实际上对于大多数人可用的垃圾收集器的选择还限于实际上实施的垃圾收集算法的子集。 (类似地, malloc也不是完美的,并且存在其问题,有多种实现方式具有不同的特性。但是,尽管这是一个有趣的话题,但是本文并未尝试对比自动和显式内存管理。)

现实情况是,与许多技术问题一样,需要权衡取舍。 根据经验,如果您使用的是可免费使用的基于Hotspot的JVM:s(Oracle / Sun,OpenJDK), 那么您最关心的就是垃圾回收器(如果您担心延迟) 。 如果您不这样做,那么垃圾回收器将不会很麻烦–除了可能选择与默认值不同的最大堆大小之外。

所谓等待时间,是指垃圾收集的暂停时间 。 垃圾收集器有时需要暂停应用程序才能完成其某些工作。 这通常被称为停止这世界的停顿(“世界”是从Java应用程序的GC说话的角度,或突变可观测宇宙(因为它是变异堆,而垃圾收集器试图收集重要的是要注意,尽管所有实际可用的垃圾收集器都在应用程序上施加了世界暂停,但这些暂停的频率和持续时间随垃圾收集器,垃圾收集器设置和应用程序行为的选择而变化很大

就像我们将看到的那样,存在垃圾收集算法,这些算法试图避免需要在停顿世界的暂停中收集整个堆。 这是一个重要属性的原因是,如果在任何时候(即使很少)停止应用程序以完全收集堆,则应用程序所遭受的暂停时间将与堆大小成正比 。 通常,这是您在关心延迟时要避免的主要事情。 也有其他问题,但这通常是一个大问题。

跟踪与参考计数

您可能听说过正在使用引用计数 (例如,cPython在大多数垃圾收集工作中都使用了引用计数方案)。 我不会谈论太多,因为它与JVM:s无关,只说两件事:

  • 计数垃圾回收的引用具有的一个属性是,将在删除最后一个引用时立即知道该对象是不可访问的。
  • 引用计数将不会检测为不可访问的循环数据结构,并且还有其他一些问题使其无法成为所有垃圾收集的最终选择。

JVM而是使用所谓的跟踪垃圾收集器。 之所以称为跟踪,是因为至少在抽象级别上,识别垃圾的过程涉及获取根集 (例如堆栈上的局部变量或全局变量之类的东西),并跟踪从那些对象到直接或间接所有对象的路径。从所述根集合可以间接到达。 一旦确定了所有可到达的(活动的)对象,就可以通过消除过程来标识符合垃圾收集器释放条件的对象。

基本停止,标记,扫动,恢复

一个非常简单的跟踪垃圾收集器使用以下过程工作:

  1. 完全暂停应用程序。
  2. 通过跟踪对象图(即,递归地遵循引用),标记所有可到达的对象(从根集开始,参见上文)。
  3. 释放所有无法访问的对象。
  4. 恢复应用程序。

在单线程环境中,这很容易想象:负责分配新对象的调用将立即返回新对象,或者,如果堆已满,则启动上述过程以释放空间,然后执行通过完成分配并返回对象。
没有一个JVM垃圾收集器像这样工作。 但是,最好理解垃圾收集器的这种基本形式,因为可用的垃圾收集器实质上是上述过程的优化。 JVM不实现这种垃圾回收的两个主要原因是:

  • 每个垃圾回收暂停将足以收集整个堆。 换句话说,它的延迟很差。
  • 对于几乎所有现实应用程序而言,它都不是执行垃圾回收的最有效方法(它具有很高的CPU开销)。

压缩与非压缩垃圾回收

垃圾收集器之间的一个重要区别是它们是否正在压缩 。 压缩是指将对象移动(在内存中)以将其收集在一个密集的内存区域中,而不是稀疏地散布在较大的区域中。

真实世界的类比:考虑一个随机空间中地板上满是东西的房间。 拿走所有这些东西并将其紧紧塞在角落里实际上就是将它们压实。 释放空间。 记住什么是压实的另一种方法是,设想其中的一台机器会像汽车一样将其压实成一块金属,从而消除了空气所占的全部空间,从而比原来的汽车占用更少的空间(但是有人指出,虽然汽车ID遭到破坏,但堆上的物体却没有!)。

相比之下,非紧凑型收集器从不移动对象。 将对象分配到内存中的特定位置后,该对象将一直保留在那里或直到释放为止。
两者都有一些有趣的属性:

  • 执行压缩收集的成本是堆上实时数据量的函数。 如果只有1%的数据处于活动状态,则仅需要压缩1%的数据(复制到内存中)。
  • 相比之下,在非紧凑型收集器中,不再可访问的对象仍然意味着记账,因为它们的存储位置必须保持释放状态,以便将来分配使用。
  • 在压缩收集器中,分配通常是通过“ 碰到指针”方法来完成的。 您有一些空间区域,并保持当前的分配指针。 如果您分配一个n字节的对象,则只需将该指针加n(我就避免了诸如多线程和暗示的优化之类的复杂性)。
  • 在一个非压实集电极,分配涉及找到其中使用一些机构,其依赖于用于跟踪的空闲存储器的可用性的确切机制来分配。 为了满足n字节的分配,必须找到n字节可用空间的连续区域。 如果找不到一个(因为堆是碎片化的 ,这意味着它由可用空间和分配的空间混合在一起),分配将失败。

现实类比:再次考虑您的房间。 假设您是一个压缩收集器。 您可以在闲暇时随意在地板上移动东西。 当您需要为地板中间的那个大沙发腾出空间时,可以四处移动其他东西以腾出适当大小的沙发空间。 另一方面,如果您是一个不紧凑的收藏家,那么地板上的所有东西都会被钉牢,并且无法移动。 尽管您有足够的可用地板空间,但大沙发可能不适合放置–只有一个单独的空间不足以容纳沙发。

分代垃圾收集

大多数现实世界中的应用程序倾向于对短期对象(即已分配的对象,短暂使用的对象,然后不再引用)执行大量分配。 分代垃圾收集器尝试利用此观察结果以提高CPU效率(换句话说,具有更高的吞吐量 )。 (更正式地说,大多数应用程序具有此行为的假设被称为弱代假设 。)

之所以称其为“世代”,是因为对象分为几代 。 收集器之间的细节会有所不同,但此时的合理近似值是将对象分为两代:

  • 年轻的一代是最初分配对象的地方。 换句话说,所有物体都始于年轻一代。
  • 老一辈是反对“花钱”的对象,因为他们在年轻一代中度过了一段时间。

代收集者通常更高效的原因是,他们与老一代分开收集年轻一代。 处于稳定状态下进行分配的应用程序的典型行为是,在收集年轻代时经常出现短暂的停顿–不经常出现,但在老一代填满并触发整个堆(旧的和新的)的完整收集时会出现较长的停顿。 如果查看典型应用程序的堆使用情况图,它将类似于以下内容:

堆使用的典型锯齿行为
吞吐量收集器使用堆的典型锯齿行为

锯齿状外观的出现是年轻一代垃圾收集的结果。 接近尾声的时候是老一代人变满了,而JVM对整个堆进行了完整的收集。 该下降结束时的堆使用量是该时间点实际活动集的合理近似值。 (注意:这是针对配置为使用默认JVM吞吐量收集器的Cassandra实例运行压力测试的图;它不反映Cassandra的即开即用行为。)

请注意,仅在该图上的任意时间点选择“当前堆使用情况” 都不会使您了解应用程序的内存使用情况 。 我不能足够强调这一点。 通常认为内存“使用”是活动集 ,而不是任何特定时间的堆使用情况。 堆的使用更多取决于垃圾收集器的实现细节。 应用程序的内存使用量对堆使用量的唯一影响是,它为堆使用量提供了一个下限
现在,回到为什么代收集者通常更高效的原因。

假设我们的假设应用是所有物体中有90% 早逝 ; 换句话说,它们永远无法生存到足以被提升为老一代的程度。 此外,假设我们的年轻一代集合实际上是紧凑的(请参阅前面的部分)。 现在收集年轻一代的成本大约是跟踪和复制它所包含的对象的10%的成本。 剩下的90%的成本很小。 年轻一代的收藏会在充满时发生,并且是世界停下来的停顿。

幸存的对象的10%可能会立即升级为老一代,或者它们可能在年轻一代中再生存一轮或两轮(取决于各种因素)。 但是,要理解的重要总体行为是,对象从年轻一代开始,并由于在年轻一代中生存提升为老一代。

(精明的读者可能已经注意到,不可能完全分开收集年轻一代–如果旧一代中的对象引用了新一代中的对象该怎么办?这确实是垃圾收集器必须处理的事情;以后的文章会谈论这个。)

优化过程很大程度上取决于年轻一代的规模 。 如果大小太大,则可能太大,以至于与收集它相关的暂停时间是一个明显的问题。 如果大小太小,则可能甚至死得很年轻的物体也不会足够快地死去, 以至于它们死后仍处于年轻一代中。

回想一下,年轻的一代是在变得饱满时收集的; 这意味着它越小,收集它的频率就越高。 进一步回想一下,当对象在年轻一代中幸存下来时,它们将被提升为老一代。 如果大多数对象(尽管早逝)都不会因为其太小而在年轻一代中死亡-他们将被提升到老一代,而代际垃圾收集器试图进行的优化将失败,而您将承担以后在老一代中收集对象的全部费用(加上从年轻一代中复制对象的前期费用)。

平行收集

拥有分代收集器的目的是为了优化吞吐量 ; 换句话说,应用程序在特定时间内完成的工作总量。 副作用是,由于垃圾收集而引起的大多数暂停也会变得更短。 但是,没有尝试消除周期性的完整收集,这意味着完成完整收集所需的暂停时间。

为了减轻这种情况,吞吐量收集器做了一件值得一提的事情:它是并行的 ,这意味着它同时使用多个CPU内核来加速垃圾收集。 确实可以缩短停顿时间,但是您可以走多远还是有一个限制–即使在线性加速的不现实完美情况下(意味着双CPU计数->收集时间的一半),您也会受到数量的限制系统上的CPU内核数。 如果要收集30 GB的堆,即使使用16个并行线程,也将花费大量时间。

用垃圾回收的话来说,并行一词用于表示同时在多个CPU内核上工作的收集器。

增量收集

垃圾回收上下文中的增量是指将需要完成的工作分成较小的块,通常目的是将应用程序暂停多个短暂的时间而不是一个长时间的暂停。 从年轻的一代收集器构成增量功的意义上讲,上述一代收集器的行为是部分增量的。 但是,从总体上看,收集过程不是增量的,因为在旧的一代变满时会发生全部堆收集。
其他形式的增量收集也是可能的; 例如,对于应用程序执行的每个分配,收集器可以执行少量的垃圾收集工作。 该概念与特定的实施策略无关。

并发收集

垃圾回收上下文中的并发是指应用程序(变异器) 同时执行垃圾回收工作。 例如,在8核系统上,垃圾收集器可能保留两个后台线程,这些线程在应用程序运行时执行垃圾收集工作。 这允许完成大量工作而不会导致应用程序暂停,通常会以一定的吞吐量和实现复杂性为代价(对于垃圾收集器实现者)。

可用的热点垃圾收集器

Hotspot中垃圾收集器的默认选择是吞吐量收集器,它是一个世代的并行压缩收集器。 完全针对吞吐量进行了优化; 在给定时间段内应用程序完成的工作总量。

CMS收集器是解决延迟/暂停时间问题的传统替代方法。 CMS代表并发标记和扫描 ,是指收集器使用的机制。 收集器的目的是最大程度地减少甚至消除长时间的停顿,将垃圾回收工作限制为较短的停顿(通常是并行)停顿,并与应用程序同时执行更长的工作相结合。 CMS收集器的一个重要属性是它紧凑,因此存在碎片问题(有关详细信息,请参阅后面的博客文章)。

在JDK 1.6和JDK 1.7的更高版本中,有一个新的垃圾收集器,称为G1 (代表Garbage First )。 像CMS收集器一样,其目的是尝试减轻或消除长时间停顿世界停顿的需求,并且它的大部分工作都是在短暂的停顿世界渐进停顿的同时进行的,其中一些工作也在​​完成中与应用程序同时进行。 与CMS相反,G1 紧凑的收集器,并且没有碎片问题的困扰-而是有其他折衷的选择(同样,在以后的博客文章中将对此进行更多讨论)。

观察垃圾收集器行为

我鼓励读者尝试使用垃圾收集器的行为。 使用jconsole(与JDK一起提供)或VisualVM (在本文较早的时候生成了该图)来可视化正在运行的JVM上的行为。 但是,尤其要开始运行JVM,以开始熟悉垃圾收集日志的输出(已更新jbellis的反馈–谢谢!):

  • -XX:+PrintGC
  • -XX:+PrintGCDetails
  • -XX:+PrintGCDateStamps
  • -XX:+PrintGCApplicationStoppedTime
  • -XX:+PrintPromotionFailure

也有用但冗长(含义在以后的文章中解释):

  • -XX:+PrintHeapAtGC
  • -XX:+PrintTenuringDistribution
  • -XX:PrintFLSStatistics=1

对于吞吐量收集器,输出非常容易读取。 对于CMS和G1,在没有介绍的情况下,输出对于分析而言更加不透明。 我希望在以后的更新中对此进行介绍。

同时,得出的结论是,每当怀疑与GC相关的问题时,上面的那些选项可能就是您要使用的第一件事。 当人们开始假设GC问题时,这几乎总是我告诉人们的第一件事。 您是否看过GC日志? 如果您还没有,那可能是在浪费时间猜测GC。

结论

我试图制作一个速成课程介绍,希望对我有启发性,但主要是作为后续文章的背景。 我欢迎任何反馈,尤其是在情况不清楚或我做出太多假设的情况下。 正如我一开始所说的那样,我希望这个系列能够被广泛的读者所接受,尽管我当然确实具有一定的专业水平。 但是,不需要垃圾收集方面的知识。 如果是,我已经失败了-请让我知道。

参考: 实用垃圾收集,第1部分–我们的JCG合作伙伴 Peter Schuller在(mod:world:scode)博客上的介绍


翻译自: https://www.javacodegeeks.com/2012/01/practical-garbage-collection-part-1.html

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

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

相关文章

mysql 导出 没有函数_没有MYSQL FILE函数的CSV导出

构建最佳CSV。你可以按照以下方式做。$filename data.csv;$csv_terminated "\n";$csv_separator ",";$csv_enclosed ";$csv_escaped "\\";$results array(1,2,3);// value$schema_insert ;$header array(a,b,c);// headerfor ($i 0…

html回复评论_3天内看了3000多篇《哈佛商业评论》,挑出来最有用的分享下

上次分享过一个工具:一键批量下载公众号历史消息(后台回复001获取)。我把《哈佛商业评论》的历史文章,全部爬了下来。该杂志被全球商业誉为“管理圣经”。我最感兴趣的一部分是:个人管理。先搜索关键词:&qu…

codeforces 732/D 二分

给出考试时间和考试需要准备的时间&#xff0c;问最早考完所有科目的时间 二分答案 NlogN 二分抄神犇的写法 感觉挺舒服的嘻嘻嘻 1 #include<bits/stdc.h>2 using namespace std;3 const int MAXN1e55;4 int N,M,d[MAXN],w[MAXN],cnt[MAXN];5 void read(int &x){6 …

网页版的svn怎样同步代码_学会使用Hdlbits网页版Verilog代码仿真验证平台

大家推荐一款网页版的 Verilog代码编辑仿真验证平台&#xff0c;这个平台是国外的一家开源FPGA学习网站&#xff0c;通过“https://hdlbits.01xz.net/wiki/Main_Page”地址链接进入网页&#xff0c;在该网页上可以进行Verilog代码的编写、综合&#xff0c;而且最后还能够仿真出…

Python的下载及安装

1、官网下载地址&#xff1a;https://www.python.org/downloads/ 2、python设置环境变量&#xff1a; 在系统变量里添加Python的安装位置 3、在cmd里输入python里即可转载于:https://www.cnblogs.com/fun0623/p/5257573.html

使用Apache ActiveMQ的JMS开发基础

去年是我尝试JMS的时候。 背后的想法和概念让我有些困惑&#xff0c;但是当我知道它的用途后&#xff0c;我很快就掌握了它。 在本文中&#xff0c;我将展示使用Apache ActiveMQ作为后端使用Java开发简单的生产者/消费者的基础。 让我们首先从概念开始&#xff0c;这是一个简单…

PLSQL 经常自动断开失去连接的解决过程

问题背景&#xff1a; 情况是这样的&#xff0c;很多开发同事的PLSQL上班时间开着8个小时&#xff0c;有时候他们出去抽烟后或者中午吃完饭&#xff0c;回来在PLSQL上面执行就报错无响应&#xff0c;然后卡住了半天动弹不了&#xff0c;非得重新登录plsql才生效&#xff0c;我猜…

使用Cobertura,JUnit,HSQLDB,JPA涵盖您的测试

你好&#xff01;你好吗&#xff1f; 今天让我们谈谈一个非常有用的工具&#xff0c;名为“ Cobertura”。 该框架与我们在另一篇文章中看到的Emma框架具有相同的功能。 Cobertura和Emma之间的主要区别在于Cobertura显示带有图形的简历页面。 如果要查看有关该主题的其他主题…

C# 基础知识总结

要学好C#&#xff0c;基础知识的重要性不言而喻&#xff0c;现将常用到的一些基础进行总结&#xff0c;总结如下&#xff1a; 01. 数据类型转换&#xff1a; 强制类型转换(Chart--> int): char crA; int i (int)(cr); 02. 委托/匿名函数/Lamda表达式&#xff1a; 委托是匿…

使用Jolokia和JMX进行客户端服务器监视

Java监视工具的选择非常广泛&#xff08;由Google提供的随机选择和顺序&#xff09;&#xff1a; javamelody 压力探头 JVisualVM 控制台 贾蒙 Java JMX Nagios插件不适用 此外&#xff0c;还有各种专用工具&#xff0c;例如ActiveMQ &#xff0c; JBoss &#xff0c; Qu…

图书管理系统数据字典_2. 结构化——数据字典

返回目录&#xff1a;Chilan Yuk&#xff1a;软件工程分析设计图库目录​zhuanlan.zhihu.com一、基本知识用于定义数据流和数据存储的结构&#xff0c;并给出构成所给的数据流和数据存储的各数据项的基本数据类型。数据字典中应该包括关于数据的如下信息一般信息&#xff08;名…

重复次数最多的 子串_每日算法系列【LeetCode 424】替换后的最长重复字符

题目描述给你一个仅由大写英文字母组成的字符串&#xff0c;你可以将任意位置上的字符替换成另外的字符&#xff0c;总共可最多替换 k 次。在执行上述操作后&#xff0c;找到包含重复字母的最长子串的长度。示例1输入&#xff1a; s "ABAB", k 2 输出&#xff1a; …

python基础(一)简单入门

一.第一个python程序 1.交互式编程 直接在命令行里面输入python即可进入python交互式命令行&#xff0c;linux下一样&#xff1a; 在 python 提示符中输入以下文本信息&#xff0c;然后按 Enter 键查看运行效果&#xff1a; 2.脚本式编程 把代码都写到文件里面&#xff0c;然后…

unbuntu 启动任务脚本_Ubuntu下服务启动脚本编写

像Nginx、MySQL等服务一样&#xff0c;在后台运行自己编写的抓取天气信息的Python脚本。1.以管理员权限新建一个服务脚本文件sudo vim /etc/init.d/weather_service2.用下列模板修改该服务脚本文件#!/bin/bash### BEGIN INIT INFO## Provides: weather_service# Required-Start…

iOS开发工具——网络封包分析工具Charles

作者 唐巧 发布于 2013年12月9日 | 1 讨论 分享到&#xff1a;微博微信FacebookTwitter有道云笔记邮件分享稍后阅读我的阅读清单简介 Charles是在Mac下常用的截取网络封包的工具&#xff0c;在做iOS开发时&#xff0c;我们为了调试与服务器端的网络通讯协议&#xff0c;常常需要…

Java Web托管选项流程图

我经常被问到的一个问题是在何处以及如何托管Java Web应用程序。 可以在带有嵌入式服务器的Eclipse中创建它很好&#xff0c;但是如何将它带给人们呢&#xff1f; 长期以来&#xff0c;对于发烧友的程序员一直没有答案。 只有昂贵和超大型的选择。 事情最近变了&#xff0c;但这…

使用Regions ADF 11g进行Master Detail CRUD操作

你好 此示例演示了如何使用Regions在表之间创建Master Detail关系。 区域的主要目的是可重用性的概念。 使用区域和有限的任务流&#xff0c;我们可以将页面重用到许多其他页面中&#xff0c;以保持相同的功能并采用更简洁的方法。 下载示例应用程序。 在此示例中&#xff0c;…

win7 mysql php apache myadmin_windows下Apache+mysql+php+phpMyAdmin的安装及配置 | 学步园

1、下载Apache ( httpd-2.2.25-win32-x86-no_ssl.msi )http://httpd.apache.org/download.cgi#apache24根据提示安装到路径(建议自定义路径)&#xff0c;NetWork Domain和Server Name都输入 localhost(访问时使用的域名);2、下载mysql (mysql-5.5.34-win32.msi )http://dev.m…

具有NetBeans,嵌入式GlassFish,JPA和MySQL数据源的Arquillian

这是一个偶然的帖子。 我一直在研究交易CDI观察者&#xff0c;并尝试使用嵌入式GlassFish对它进行一些集成测试。 但是令人惊讶的是&#xff0c;这种方法不能很好地工作&#xff0c;我仍在弄清楚&#xff0c;使用普通的嵌入式GlassFish时问题出在哪里。 同时&#xff0c;我转到…

jsp mysql 音乐网站_Maven+JSP+SSM+Mysql实现的音乐网站

项目简介本系统基于MavenJSPSSMMysql实现的音乐网站。主要实现的功能有音乐播放、下载、上传等几个模块。难度等级&#xff1a;中等技术栈编辑器Eclipse Version: 2020-03 (4.15.0)前端技术基础&#xff1a;htmlcssJavaScript框架&#xff1a;JQueryBootstrap后端技术SpringSpr…