leftso 691 0 2018-04-14 07:10:00 编程技术 Java 学习Java 垃圾回收

logo-cover-学习java垃圾回收
    垃圾回收(GC)一直是Java受欢迎背后的重要特性之一。垃圾回收是Java中用于释放未使用的内存的机制。本质上,它追踪所有仍在使用的对象,并将剩下的标记为垃圾。Java的垃圾回收被认为是一种自动内存管理模式,因为程序员不必指定对象准备被释放。垃圾回收在低优先级的线程上运行。
    在本教程中,我们将学习java中内存分配/解除分配有关的各种概念,在场景后面运行的算法以及您必须自定义此行为的选项。

对象生命周期

Java的对象生命周期可以分为三个阶段:

  1. 对象创建

    要创建一个对象,通常我们使用new关键字。例如

    Object obj = new Object();

    创建对象时,会分配特定数量的内存用于存储该对象。分配的内存量可以根据体系结构和JVM而有所不同。

  2. 对象在使用中

    到时候,对象被应用程序的其他对象使用(其他活动对象具有指向它的引用)。在使用过程中,对象驻留在内存中,并可能包含对其他对象的引用。

  3. 对象破坏

    垃圾回收系统监视对象,并在可行的情况下统计每个对象的引用数量。当没有对象的引用时,就没有办法用当前运行的代码来访问它,所以释放相关联的内存是非常合理的。

垃圾回收算法

对象创建是通过您编写的代码完成的; 以及您用来使用其提供的功能的框架。作为一名Java开发人员,我们不需要取消分配内存或取消引用对象。它由gargabe收集器在JVM级别自动完成。自从Java诞生以来,已经有很多关于在场景后面运行的算法的更新来释放内存。让我们看看他们是如何工作的?

马克和扫描

它是初始和非常基本的算法,分两个阶段运行:

  1. 标记活动对象 - 找出所有仍然活着的对象。
  2. 删除无法访问的对象 - 删除其他所有内容 - 所谓的死亡和未使用的对象。

首先,GC将一些特定对象定义为垃圾回收。例如当前正在执行的方法的本地变量和输入参数,活动线程,已加载类的静态字段和JNI引用。现在,GC遍历内存中的整个对象图,从这些根开始,并从根到下一个对象的引用。GC访问的每个对象都被标记为活动。

应用程序线程需要停止标记才能发生,因为如果它不断变化,它不能真正遍历图形。它被称为停止世界暂停

第二阶段是摆脱未使用的对象来释放内存。这可以通过多种方式完成,例如

  • 正常删除 - 正常删除将未引用的对象移除到空闲空间并保留引用的对象和指针。内存分配器(散列表的种类)持有对可以分配新对象的可用空间块的引用。

它经常被当作mark-sweep算法。
1

  • 压缩删除 - 仅删除未使用的对象效率不高,因为可用内存块分散在存储区域中,并且如果创建的对象足够大并且未找到足够大的内存块,将导致OutOfMemoryError。

为了解决这个问题,在删除未引用的对象之后,对其余的引用对象进行压缩。这里的压缩指的是将参考对象移动到一起的过程。这使得新的内存分配变得更加容易和快速。

它经常被当作mark-sweep-compact算法。

2
  • 删除与复制 - 这与标记和补偿方法非常相似,因为它们也会重新定位所有活动对象。重要的区别是重定位的目标是不同的存储区域。

它经常被当作mark-copy算法。
3

并发标记扫描(CMS)垃圾回收

CMS垃圾回收本质上是一种升级的标记和扫描方法。它使用多线程扫描堆内存。它进行了修改,以利用更快的系统并提高性能。

它试图通过与应用程序线程同时进行大部分垃圾回收工作来尽量减少由于垃圾回收造成的暂停。它使用年轻一代中的并行停止世界标记复制算法和老一代中主要是并发的标记扫描算法。

要使用CMS GC,请使用下面的JVM参数:

-XX:+UseConcMarkSweepGC
CMS GC优化选项
标识 描述
-XX:+ UseCMSInitiating \ OccupancyOnly 表示您希望仅将占用情况用作启动CMS回收操作的标准。
-XX:CMSInitiating \ OccupancyFraction = 70 设置CMS生成占有率以启动CMS回收周期。
-XX:CMSTriggerRatio = 70 这是在MinHeapFreeRatioCMS周期开始之前分配的CMS生成的百分比。
-XX:CMSTriggerPermRatio = 90 设置MinHeapFreeRatio开始CMS回收周期之前分配的CMS永久生成中的百分比。
-XX:CMSWaitDuration = 2000 使用该参数指定允许CMS等待年轻回收的时间。
-XX:+ UseParNewGC 选择使用并行算法进行年轻空间回收
-XX:+ CMSConcurrentMTEnabled 为并发阶段启用多个线程。
-XX:ConcGCThreads = 2 设置用于并发阶段的并行线程的数量。
-XX:ParallelGCThreads = 2 设置您想要用于停止世界阶段的并行线程的数量。
-XX:+ CMSIncrementalMode 启用增量CMS(iCMS)模式。
-XX:+ CMSClassUnloadingEnabled 如果未启用,CMS将不会清除永久空间。
-XX:+ ExplicitGCInvokes \并发 这允许System.gc()触发并发回收而不是完整的垃圾回收周期。

串行垃圾回收

该算法对老一代的年轻一代和标记扫描压缩使用标记复制。它适用于单个线程。执行时,它会冻结所有其他线程,直到垃圾回收操作结束。

由于串行垃圾回收的线程冻结性质,它只适用于非常小的程序。

要使用串行GC,请使用下面的JVM参数:

-XX:+UseSerialGC

并行垃圾回收

Simimar串行GC,它用于mark-copy年轻一代和mark-sweep-compact老一代。多个并发线程用于标记和复制/压缩阶段。您可以使用-XX:ParallelGCThreads=N选项配置线程数。

当您的主要目标是通过有效使用现有系统资源来提高吞吐量时,并行垃圾回收器适用于多核机器。使用这种方法,GC循环时间可以大大减少。

直到Java 8,我们已经看到并行GC作为默认垃圾回收器。从Java 9开始,G1是32位和64位服务器配置上的默认垃圾回收器。- JEP [248]

要使用并行GC,请使用下面的JVM参数:
-XX:+UseParallelGC

G1垃圾回收

G1(垃圾优先)垃圾回收器在Java 7中可用,旨在成为CMS回收器的长期替代品。G1回收器是一个并行的,并发的,逐步压缩的低暂停垃圾回收器。

这种方法涉及将内存堆分割成多个小区域(通常为2048)。每个地区都被标记为年轻一代(进一步分为伊甸园地区或幸存地区)或老一代。这样GC就可以避免一次回收整个堆,而是逐步处理问题。这意味着一次只考虑一小部分区域。
4

 

G1会跟踪每个区域包含的实时数据量。该信息用于确定包含垃圾最多的区域; 所以他们首先被回收。这就是为什么它是名称垃圾优先回收

就像其他算法一样,不幸的是,压缩操作使用“ 停止世界”方法进行。但根据设计目标,您可以为其设定特定的性能目标。您可以配置暂停持续时间,例如在任何给定秒内不超过10毫秒。Garbage-First GC将尽最大努力以高概率实现这一目标(但不能确定,由于OS级别的线程管理,这很难实时)。

如果您想在Java 7或Java 8机器中使用,请使用JVM参数如下:

-XX:+UseG1GC
G1优化选项
描述
-XX:G1HeapRegionSize =16米 堆区的大小。该值将是2的幂,可以从1MB到32MB。目标是基于最小的Java堆大小,大约有2048个区域。
-XX:MaxGCPauseMillis = 200 为所需的最大暂停时间设置一个目标值。默认值是200毫秒。指定的值不适应您的堆大小。
-XX:G1ReservePercent = 5 这决定了堆中的最小预留量。
-XX:G1ConfidencePercent = 75 这是置信度系数暂停预测启发式。
-XX:GCPauseIntervalMillis = 200 这是每个MMU的暂停间隔时间片,以毫秒为单位。

GC自定义选项

GC配置标志

标识 描述
-Xms2048m -Xmx3g 设置初始和最大堆大小(年轻空间加上终身空间)。
-XX:+ DisableExplicitGC 这将导致JVM忽略应用程序的任何System.gc()方法调用。
-XX:+ UseGCOverheadLimit 这是用于限制在抛出OutOfMemory错误之前在垃圾回收中花费的时间的使用策略。
-XX:GCTimeLimit = 95 这限制了OutOfMemory抛出错误之前花在垃圾回收上的时间比例。这用于GCHeapFreeLimit
-XX:GCHeapFreeLimit = 5 这会在引发OutOfMemory错误之前设置完整垃圾回收之后可用空间的最小百分比。这用于GCTimeLimit
-XX:InitialHeapSize =3克 设置初始堆大小(年轻空间加上终身空间)。
-XX:MaxHeapSize =3克 设置最大堆大小(年轻空间加上终身空间)。
-XX:新尺寸=128米 设置年轻空间的初始大小。
-XX:MaxNewSize =128米 设置年轻空间的最大尺寸。
-XX:SurvivorRatio = 15 将单个生存者空间的大小设置为Eden空间大小的一部分。
-XX:PermSize =512米 设置永久空间的初始大小。
-XX:MaxPermSize参数=512米 设置永久空间的最大尺寸。
-Xss512k 以字节为单位设置专用于每个线程的堆栈区域的大小。

GC日志记录标志

标识 描述
-verbose:gc或-XX:+ PrintGC 这将打印基本垃圾回收信息。
-XX:+ PrintGCDetails 这将打印更详细的垃圾回收信息。
-XX:+ PrintGCTimeStamps 您可以为每个垃圾回收事件打印时间戳。秒是连续的并从JVM开始时间开始。
-XX:+ PrintGCDateStamps 您可以为每个垃圾回收事件打印日期戳。
-Xloggc: 使用这个你可以重定向垃圾回收输出到一个文件而不是控制台。
-XX:+打印\ TenuringDistribution 您可以在每个回收周期后打印有关年轻空间的详细信息。
-XX:+ PrintTLAB 您可以使用此标志打印TLAB分配统计信息。
-XX:+ PrintReferenceGC 使用此标志,您可以在停止世界暂停期间打印参考处理的时间(即弱,软等等)。
-XX:+ HEAPDUMP \ OnOutOfMemoryError 这会在内存不足的情况下创建堆转储文件。

总结

所以在这个java垃圾回收教程中,我们了解了以下内容 -

  1. 对象生命周期分为3个阶段,即对象创建,对象使用和对象破坏。
  2. 如何mark-sweepmark-sweep-compact以及mark-copy机制炒菜锅。
  3. 不同的单线程和并发GC算法。
  4. 直到Java 8,并行GC是默认算法。
  5. 自java 9以来,G1已被设置为默认的GC算法。
  6. 此外,还有各种标志来控制垃圾回收算法的行为并记录任何应用程序的有用信息。