JVM将堆空间划分为新生代和老年代,如此花费是为了更高效的进行垃圾回收。
- 简化创建对象的内存分配,新创建的对象都会放到新生代
- 针对新生代和老年代的特点,使用不同的垃圾回收策略。
面向对象编程中的对象,广泛的研究表明,对象大多是朝生夕死,并且已经在JVM上存活较长时间的对象很少引用新生的对象,基于这两方面的原因,把新生对象放到新生代,GC可以更快查找可以被回收的对象
新生代的区域划分
Sun/Oracle的HotSpot JVM将新生代做了细分,HotSpot将新生代划分为3个区域,较大的区域称为"Eden",两个较小的幸存者空间(survisor spaces),这两个幸存者空间一个称为From,另一个称为To。一轮GC过程中,Eden活下来的对象将被移动到幸存者空间,这些对象将在幸存者空间呆上一段时间(呆在这个阶段期间,这些对象可能要经历几次GC),如果几次GC后,这写位于幸存者空间的对象依然存活,那么它们将被移动到老年代。因此,幸存者空间就是给进入新生代的对象更多点呆在新生代的时间。每次GC时,Eden和幸存者空间都要被扫描以确定哪些对象要被回收。
新生代垃圾回收的过程
基于新生代中的对象在经历过一次GC后,大多数对象都会被回收的假设,新生代垃圾会采用复制的策略:
1. 在GC刚开始的时候,Survior的To空间是空的,对象只能存在于Eden或者From。
2. 随着GC的进行,
2.1 Eden空间依然被引用的对象将被移动到To空间。
2.2 From空间,这个空间中依然被引用的对象的处理依赖于它们的存活了的多少时间。如果它们的存活周期没有达到某个阀值(tenuring threshold,表示经历了几次GC依然存活),那 么它们也要被移动到To,否则它们将被移动到老年代。
3. 当这个copy的过程结束后,Eden和From空间中的对象是可被回收了(新生代所有存活下来的对象要么去了To,要么去了老年代)。在Eden,From向To空间移动的过程中,To空间有可能满了,那么剩下的对象,将直接移动到老年代。
4. 最后一步,From和To交换角色,因此在下一轮GC开始时,To是空的,而From则包含了所有新生代上轮GC时存活下来的对象。
下图所示是新生代GC开始时的状态以及GC结束时的状态
新生代GC过程总结
刚创建的对象在放在Eden,然后在新生代GC时,可能被移动到To空间。如果对象在几轮年轻代垃圾回收之后依然存活,那么它最终会被移动到老年代。对老年代的垃圾回收需要更大的代价,这需要更高效的GC算法(老年代不能使用简单的复制,因为没有空间可以复制了)。因此,新生代的堆空间容量是非常重要的,如果新生代空间太小,那么新生代的对象很快就会被移动到老年代(老年代垃圾回收的代价要远远超过新生代);反之,如果新生代过大,那对于长时间存活而最后到达老年代的对象,就会导致很多不必要的复制(每轮GC都要复制)。一次需要在新生代空间大小上取一个合适的值,以适应特定的应用。JVM提供了一系列的选项用于对新生代的容量调整。
新生代相关的JVM选项
-XX:NewSize and -XX:MaxNewSize
-Xms和-Xmx分别表示堆内存的最小值和最大值,--XX:NewSize和-XX:MaxNewSize分别表示新生代的最小值和最大值。需要注意的是,--XX:NewSize和-XX:MaxNewSize设置的新生代的容量,新生代设置的越大,那么老年代则越小。实际中,基于稳定性考虑,新生代的大小应该小于老年代的堆大小,因为在最糟糕的情况下,GC有可能将新生代所有的对象移动到老年代,因此,新生代堆的大小上限是-Xmx/2。
基于性能的考虑,新生代的初始大小设置为--XX:NewSize,这个值的设置也是一个参考值。
-XX:NewRatio
通过-XX:NewRation这个选项来显式的指定新生代和老年代的大小比例。通过这种相对大小的方式,可以让JVM在运行时由于动态调整堆大小时,动态的调整新生代的大小。-XX:NewRatio=3表示老年代是新生代的3倍,即新生代占堆空间的1/4,而老年大则占堆空间的3/4.
如果既设置了-XXNewSize,-XX:MaxNewSize,也设置了-XX:NewRatio,那么JVM首先尝试将新生代的大小按照新老比例进行设置(-XX:NewRatio),但是最小值不能低于-XXNewSize,最大值不能超过--XX:MaxNewSize
-XX:SurvivorRatio
-XX:SurvivorRatio用来设置在新生代内部,Eden区与Survior区的大小比例关系。比如-XX:SurvivorRatio=10表示Eden区域的大小时Survivor的From/To区域的10倍,也就是说,Eden占新生代的10/12,From和To各占1/12。
-XX:+PrintTenuringDistribution
使用-XX:+PrintTenuringDistribution这个选项是让JVM在每次新生代GC时,打印出survivor区域的对象的存活周期,比如:
Desired survivor size 75497472 bytes, new threshold 15 (max 15)
- age 1: 19321624 bytes, 19321624 total
- age 2: 79376 bytes, 19401000 total
- age 3: 2904256 bytes, 22305256 total
第一行信息是"To"空间的大小约75MB。新生代经历15次GC依然存活的,将从survivor区域移动到老年代。
下面的几行则显示了经历了几次新生代GC的对象的空间利用情况。例子中的数目表明:大约19M的对象经历了一次GC,大约79KB经历了两次GC,大约3MB经历了3次GC。在每行的最后,是在这个age范围内所包含的所有对象占用的空间,比如对个age 2,它包含的总数包括age 1对象占用的空间加age 2对象占用的空间。因此,"total"这个值意味着"To"空间当前大概包含22M对象数据。因为”To“空间的可用空间是75MB并且threshold是15,因此,当前没有对象需要移动到老年代。
再来看一下新一轮GC的情况:
Desired survivor size 75497472 bytes, new threshold 2 (max 15)
- age 1: 68407384 bytes, 68407384 total
- age 2: 12494576 bytes, 80901960 total
- age 3: 79376 bytes, 80981336 total
- age 4: 2904256 bytes, 83885592 total
比较两组数据,可以看到如下信息
1. 可见原来的age 1变为后面的age 2, 原来的age 2变为后面的age 3, 原来的age 3变为后面的age 4
2. 原来age1大概有19M,而后面的age2只有12M,也就说,这轮GC,有大概7M的内容被回收。
3. ,新一轮GC增加了大概68M的新增对象进入age 1。也就说,在这一轮GC中,JVM从Eden区移动了大概68M的数据进入To空间
4.在上面的示例中,To空间已经达到将近84M,超过75MB。因此,JVM把tenuring threshold从15降低到2,因此,接下来新一轮GC,那么To空间的对象,要么生命到期而被回收,要么进入老年代。
注:tenuring threshold参数的含义是控制对象经历多少次Minor GC才从新生代晋升到老年代代
-XX:InitialTenuringThreshold, -XX:MaxTenuringThreshold and -XX:TargetSurvivorRatio
【TBD:这段需要重写】
-XX:+PrintTenuringDistribution这个选项的输出结果可以由多个选项进行调整。
通过
-XX:InitialTenuringThreshold
和-XX:MaxTenuringThreshold可以设置tenuring threshold的初始值和最大值。并且,我们也可以通过
-XX:TargetSurvivorRatio来在新生代GC结束时,用于指定"To"的目标使用率。比如同时设置如下两个选项,
-XX:MaxTenuringThreshold=10 -XX:TargetSurvivorRatio=90设置了tenuring threshold的上限是10,并且指定了"To"空间的目标使用率是90%。如下两个场景:
1.如果-XX:+PrintTenuringDistribution显示的结果表示它们在最后达到最大tenuring threshold前经历了很多次GC,通常意味着
-XX:MaxTenuringThreshold的设置偏大。
2.
The tuning knobs shown in the output of -XX:+PrintTenuringDistribution
can be adjusted by various flags. With -XX:InitialTenuringThreshold
and -XX:MaxTenuringThreshold
we can set the initial and maximum value of the tenuring threshold, respectively. Additionally, we can use -XX:TargetSurvivorRatio
to specify the target utilization (in percent) of “To” at the end of a young generation GC. For example, the combination -XX:MaxTenuringThreshold=10 -XX:TargetSurvivorRatio=90
sets an upper bound of 10 for the tenuring threshold and a target utilization of 90 percent for the “To” survivor space.
While there are different approaches to use these flags to tune young generation behavior, no general guideline is available. We restrict ourselves to two cases that are pretty clear:
- If the tenuring distribution shows that many objects just grow older and older before finally reaching the maximum tenuring threshold, this indicates that the value of
-XX:MaxTenuringThreshold
may be too large.
- If the value of
-XX:MaxTenuringThreshold
is larger than 1 but most objects never reach an age larger than 1, we should take a look at the target utilization of “To”. Should the target utilization never be reached, then we know that all young objects get collected by the GC, which is exactly what we want. However, if the target utilization is frequently reached, then at least some of the objects beyond age 1 have been moved into the old generation, and maybe prematurely so. In this case, we can try to tune the survivor spaces by increasing their size or target utilization.
本文参考:https://blog.codecentric.de/en/2012/08/useful-jvm-flags-part-5-young-generation-garbage-collection/
- 大小: 839.6 KB
分享到:
相关推荐
JVM 内存分配与垃圾回收详解 Java 虚拟机(JVM)是 Java 语言的 runtime 环境,它提供了一个平台独立的方式来执行 Java 字节码。JVM 内存分配与垃圾回收是 JVM 中两个非常重要的概念,本文将对 JVM 内存分配与垃圾...
JVM内存模型与垃圾回收是Java性能优化的关键部分。JVM(Java Virtual Machine)内存模型分为多个区域,包括新生代(New Generation)、老年代(Old Generation)和永久代(Permanent Generation)。新生代又细分为...
- **分代收集(Generational GC)**:根据对象的生命周期,将堆分为新生代和老年代,不同年代采用不同的垃圾回收策略。 3. **垃圾回收器**: - **Serial GC**:单线程的垃圾回收器,适合轻量级应用。 - **...
Java虚拟机(JVM)的垃圾回收(GC)机制是Java程序高效运行的关键部分,它自动管理内存,释放不再使用的对象以避免内存泄漏。本文主要探讨JVM堆内存的结构和GC的工作原理,以及如何进行性能调优。 JVM堆是Java应用...
Java虚拟机(JVM)是Java程序运行的基础,它的核心组成部分之一就是垃圾回收(Garbage Collection,简称GC)。GC是JVM自动管理内存的主要方式,它负责识别并清理不再使用的对象,以避免内存泄漏和资源浪费。理解并...
在Java虚拟机(JVM)中,垃圾回收(Garbage Collection, GC)是自动管理内存的重要机制,它负责识别并释放不再使用的对象所占用的内存空间。GC的主要目标是避免内存泄漏,确保程序的稳定性和高效运行。这篇博客将...
在Java编程中,JVM(Java虚拟机)的垃圾回收机制是自动管理内存的重要部分。垃圾回收机制负责回收那些不再被程序使用、即无法达到的对象所占用的内存空间。我们通过深入探讨以下几个关键点来理解JVM垃圾回收机制的...
Java虚拟机(JVM)是Java程序运行的基础,它的核心组成部分之一就是垃圾回收器(Garbage Collector, GC),以及内存分配策略。理解这些概念对于优化Java应用性能至关重要。本篇文章将深入探讨JVM的垃圾回收机制以及...
Java虚拟机(JVM)中的垃圾回收器(Garbage Collector, GC)是Java程序自动管理内存的关键组件。垃圾回收器负责识别不再使用的对象并回收它们所占用的内存,以防止内存泄漏并确保程序的稳定运行。理解不同类型的垃圾...
Java虚拟机(JVM)是Java程序运行的基础,它的内存管理与垃圾回收机制对于程序的性能至关重要。在Java中,内存分为堆内存、栈内存、方法区、程序计数器和本地方法栈五个主要区域。下面我们将深入探讨这些区域以及...
**JVM之垃圾回收器** Java虚拟机(JVM)是Java编程语言的核心组成部分,它负责执行字节码并管理程序运行时的内存。在JVM的内存模型中,垃圾回收(Garbage Collection, GC)是一项重要的功能,它自动识别并清理不再...
在本篇文章中,我们将对比CLR和JVM的垃圾回收机制,从分代机制、回收模式、回收算法到查找存活对象的技术,深入探究它们之间的异同。 分代式垃圾回收是CLR和JVM的共同策略。该策略基于“弱代假设”,即大多数对象的...
Java虚拟机(JVM)内存管理和垃圾回收是Java编程中至关重要的概念,它们直接影响着程序的性能和稳定性。本文将详细解析JVM内存结构以及垃圾回收机制。 首先,JVM内存主要分为四个区域: 1. **堆(Heap)**:这是...
垃圾回收是JVM自动进行内存管理的一种机制,其主要目标是回收不再使用的对象所占用的内存空间,以防止内存泄漏。GC分为多个阶段: 1. **标记(Marking)**:确定哪些对象是“活的”,哪些是可回收的。常见的算法有...
1. 避免大量的短期对象创建,以减少新生代垃圾回收的压力。 2. 合理设置堆大小,避免频繁的Full GC。 3. 使用适当的垃圾回收器,根据应用需求选择平衡响应时间和内存利用率的策略。 4. 监控和分析GC日志,找出性能...
Java虚拟机(JVM)的垃圾回收(Garbage Collection, GC)是Java编程语言中一个重要的特性,它自动管理程序的内存,确保无用的对象被有效地释放,避免内存泄漏。理解JVM垃圾回收机制对于优化Java应用性能至关重要。 ...
#### 三、垃圾回收的具体流程 **3.1 分代垃圾回收机制** Java虚拟机采用了一种称为分代假设的策略,即大部分对象很快就会变成垃圾。基于这一假设,JVM将堆内存划分为不同的区域,不同区域采用不同的垃圾回收策略。...
垃圾回收的参数调整是JVM调优的重要部分,包括设置堆大小、新生代与老年代的比例、选择合适的垃圾收集器等。通过合理的配置,可以优化应用程序的性能,避免因垃圾回收导致的系统响应慢或者频繁Full GC等问题。 总之...