美文网首页
Generations

Generations

作者: taj3991 | 来源:发表于2019-12-06 12:55 被阅读0次

    Java SE平台的优势之一在于,它使开发人员免受内存分配和垃圾回收的复杂性的困扰。但是,当垃圾收集是主要瓶颈时,了解此隐藏实现的某些方面很有用。垃圾收集器对应用程序使用对象的方式进行了假设,这些反映在可调整的参数中,可以调整这些参数以提高性能,而又不牺牲抽象的功能。

    如果无法从正在运行的程序中的任何指针访问对象,则该对象被视为垃圾。最简单的垃圾回收算法会遍历每个可访问对象。剩下的任何对象都被视为垃圾。这种方法所花费的时间与活动对象的数量成正比,这对于维护大量活动数据的大型应用程序是不允许的。

    虚拟机合并了许多不同的垃圾收集算法,这些算法使用分代收集进行组合。原始的垃圾收集检查堆中的每个活动对象,而分代收集则利用大多数应用程序的经验观察到的属性,以最大程度地减少回收未使用的(垃圾)对象所需的工作。这些观察到的特性中最重要的是弱代假设,该假设指出大多数物体只能存活很短的时间。

    图3-1“对象生命周期的典型分布”中的蓝色区域是对象生命周期的典型分布。x轴是对象寿命,以分配的字节为单位。y轴上的字节数是具有相应生存期的对象中的总字节数。左侧的尖峰表示分配后可以回收的对象(换句话说,已“死亡”)。

    有些对象的寿命更长,因此分布向右延伸。例如,通常有一些在初始化时分配的对象,这些对象一直存在,直到进程退出。在这两个极端之间的是在某些中间计算过程中存在的对象,在此处被视为初始峰值右侧的块。一些应用程序的外观分布非常不同,但是令人惊讶的是,大量应用程序具有这种总体形状。通过关注大多数对象“年轻”的事实,可以进行有效的收集。

    为了针对这种情况进行优化,需要分代管理内存(保存不同年龄对象的内存池)。当各个区域填满时,垃圾收集会在每个区域中发生。绝大多数对象分配在专用于年轻对象(年轻一代)的池中,并且大多数对象在那里死亡。当年轻一代填满时,将导致次要集合,其中仅收集年轻一代。不回收其他区域的垃圾。假设弱的世代假设成立并且年轻一代中的大多数对象都是垃圾并且可以回收,可以优化次要集合。首先,这种收集的费用与所收集的有生命物体的数量成正比;可以很快收集到充满死亡对象的年轻一代。通常,在每个次要收集期间,来自年轻世代的尚存对象的一部分会移交给终身代。最终,老年代将填满并且必须被收集,从而产生一个major gc,其中将收集整个堆。major gc的持续时间通常比minor gc集合的持续时间长得多,因为涉及的对象数量很多。

    如“ Ergonomics”部分所述,人体工程学动态选择垃圾回收器,以在各种应用程序上提供良好的性能。串行垃圾收集器是为具有小型数据集的应用程序设计的,其默认参数被选择为对大多数小型应用程序有效。并行或吞吐量垃圾收集器旨在与具有中大型数据集的应用程序一起使用。通过Ergonomics选择的堆大小参数以及自适应大小策略的功能旨在为服务器应用程序提供良好的性能。这些选择在大多数(但不是全部)情况下都有效,这导致了本文档的中心宗旨:

    如果垃圾收集成为瓶颈,则您很有可能必须自定义总堆大小以及各个世代的大小,检查详细的垃圾收集器输出,然后探索各个性能指标对垃圾收集器参数的敏感性。

    图3-2除并行收集器和G1之外的分代默认排列


    在初始化时,最大地址空间实际上是保留的,除非需要,否则不会分配给物理内存。为对象存储器保留的完整地址空间可以分为年轻代和老年代。

    年轻一代由eden和两个survivor区组成。大多数对象最初是在eden中分配的。

    一个sruvivor空间随时都是空的,可作为eden中任何对象的目的地;另一个survivor空间是下一个复制集合期间的目的地。以这种方式在survivor空间之间复制对象,直到它们足够老到可以使用(复制到使用对象的老年代)为止。

    性能考量

    有两种主要的垃圾收集性能度量:

    • 吞吐量是长时间内未花费在垃圾回收上的总时间的百分比。
    • 暂停是指由于正在进行垃圾回收而导致应用程序无响应的时间。

    用户对垃圾回收有不同的要求。例如,某些人认为Web服务器的正确度量标准是吞吐量,因为垃圾收集期间的暂停可能是可以容忍的,或者可能被网络延迟所掩盖。但是,在交互式图形程序中,即使短暂的暂停也会对用户体验产生负面影响。

    一些用户对其他注意事项敏感。足迹是流程的工作集,以页和缓存行为单位。在具有有限物理内存或许多进程的系统上,占用空间可能决定可伸缩性。即时性是指对象死掉和内存可用之间的时间,这是分布式系统(包括远程方法调用(RMI))的重要考虑因素。

    通常,为特定分代选择大小是这些考虑之间的权衡。例如,一个非常大的年轻一代可以最大化吞吐量,但是这样做会以占用空间,及时性和暂停时间为代价。可以通过使用少量的年轻一代来最小化年轻一代的停顿,但会降低吞吐量。一代的大小不会影响另一一代的收集频率和暂停时间。

    没有选择世代大小的正确方法。最佳选择取决于应用程序使用内存的方式以及用户需求。因此,虚拟机对垃圾收集器的选择并非总是最佳选择,并且可以用“调整世代大小”部分中介绍的命令行选项覆盖。

    衡量

    使用特定于应用程序的度量标准可以最好地衡量吞吐量和占用空间。例如,可以使用客户端负载生成器来测试Web服务器的吞吐量,而可以使用pmap命令在Solaris操作系统上测量服务器的占用空间。但是,通过检查虚拟机本身的诊断输出,很容易估算出由于垃圾收集而引起的暂停。

    命令行选项-verbose:gc使有关堆和垃圾收集的信息在每个收集处输出。例如,以下是大型服务器应用程序的输出:

    输出显示两个minor gc,然后是一个full gc。箭头之前和之后的数字(例如,第一行的325407K-> 83000K)分别表示垃圾回收之前和之后的活动对象的组合大小。在进行次要收集之后,该大小包括一些垃圾(不再存在)但无法回收的对象。这些对象包含在使用期限的代中或从使用期限的代中引用。

    括号中的下一个数字(例如,从第一行起再次为(776768K))是堆的已提交大小:可用于Java对象而不需要从操作系统请求更多内存的空间量。请注意,此数字仅包括幸存者空间之一。除了在垃圾回收期间,在任何给定时间仅将使用一个幸存空间来存储对象。

    该行的最后一项(例如0.2300771秒)指示执行收集所需的时间,在这种情况下约为四分之一秒.

    第三行中主要major gc的格式相似。

    -verbose:gc产生的输出格式可能会在将来的版本中更改。

    命令行选项-XX:+ PrintGCDetails导致要打印的有关集合的其他信息。此处显示了使用串行垃圾收集器的-XX:+ PrintGCDetails输出示例。

    这表明minor gc回收了约98%的年轻代,DefNew:64575K-> 959K(64576K),并花费了0.0457646秒(约45毫秒).

    整个堆的使用率降低到约51%(196016K-> 133633K(261184K))​​,最后的时间为0.0459067秒,表明该集合(除年轻一代的集合之外)有一些额外的开销。

    -XX:+ PrintGCDetails产生的输出格式可能会在将来的版本中更改。

    选项-XX:+ PrintGCTimeStamps在每个集合的开始处添加一个时间戳。这对于查看垃圾收集发生的频率很有用。

    收集开始到应用程序执行大约111秒。次要收集大约在同一时间开始。此外,还显示了Tenured所描绘的major gc的信息。老年代使用率降低到约10%(18154K-> 2311K(24576K)),并花费了0.1290354秒(约130毫秒)

    原文

    https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/generations.html

    相关文章

      网友评论

          本文标题:Generations

          本文链接:https://www.haomeiwen.com/subject/brsjgctx.html