JVM中将对象预留在新生代

原创 2016年08月31日 00:16:41

            JVM中将对象预留在新生代

         可以看出JVM的大部分对象在创建时,都是在新生代的Eden中分配内存空间来存储的,只有极少数的对象会被直接分配到老年代。这一现象的是由于JVM对于对象存储设计的分配策略造成的。为了更好的了解这个策略及其对于对象回收机制的影响,笔者认为有必要讲解一下JVM的内存分配和回收策略。首先,来看看JVM将对象分配在新生代情况。

       

         在大多数的情况下,对象产生于新生代的Eden中(除了比较大的对象以外)。当Eden中的空间逐渐被新的对象分配占满时,就会出现Eden区域无法为后面产生的对象分配足够的存储空间的现象。此时,就会引发JVM 进行一次Minor GC。

         由于通过研究发现,大部分的对象都是占用空间比较小而且生命周期很短的,所以对于这些对象来说,其一生基本上都是在Eden或者新生代中度过的。为什么这样说呢?因为对于一些小的对象、生命周期比较短的对象,它们大部分都很难经历几次Minor GC而仍然处于存活状态。大部分对象都在这几次Minor GC的过程中结束了生命周期。进而其占用的内存被系统GC回收了,只有少数一部分才会进入老年代。所以出于对对象生命周期及大小的考虑,把小对象或者生命周期较短的对象放入到新生代,或者预留在新生代是比较合理的,毕竟如果对象过早的放入老年代,会增加Full GC的风险,这是编程开发者极其不远看到的,它会造成巨大的性能问题。

        基于此JVM在新生代划分出了两个Survivor区域用来处理这些预留在新生代的对象,这两个Survivor区域就是From(Survivor1)和To(Survivor2)。并且在进行Minor GC时,新生代一般采用的是复制算法。其具体过程如下:

1)      在为新对象分配内存空间时,发现新生代的Eden区域已满,触发Minor GC;

2)      将Eden区域中的存活的对象复制到To区域;(To未满)

3)      将From区域中仍然存活的对象复制到To区域;(To未满且From中不存在长期存活的对象)

4)      将From区域与To区域互换;

5)      清空Eden与交换后的To区域(原From区域);

从整个过程来看,新的对象在进行前几次Minor GC时,都会被预留在新生代中。但是也有一些潜在的问题,如在进行GC时,To区域满了怎么办?进行对象进行多次Minor GC仍然在新生代,造成新生代内存资源的占用,影响性能等问题。不用着急,这些问题在后面几个小结,都会有解答。

        下面,通过图4-3来为读者形象的解释Minor GC中,对象在新生代中移动。

图4-3 Minor GC 前后新生代内存分布


为了进一步了解,JVM把一些小对象预留在新生代的情况,这里需要读者动手来演示一个简单的例子,更深入的了解这一内存分配策略。

案例代码如下

//案例4.2
package Example;
/**
  *@author DT大数据梦工厂  
  * 新浪微博:http://weibo.com/ilovepains/  
  * Created by pc-Hipparic on 2016/5/9.  
 */
public class Test4_2 {

	private static int KB = 1024;
	public static void main(String[] args) {
		byte[] object1, object2, object3, object4;
		object1 = new byte[204 * KB];
		object2 = new byte[512 * KB];
		object3 = new byte[204 * KB];
		object2 = new byte[100 * KB];
		object4 = new byte[512 * KB];
		object1 = new byte[102 * KB];
		object4 = new byte[500 * KB]; 	//会发生Minor GC
		object3 = new byte[202 * KB];
	}
}

JVM 参数配置如下:

-Xms15M -Xmx15M -Xss128k -XX:+PrintGCDetails -XX:NewRatio=2 -XX:SurvivorRatio=2
-XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:./gclogs

这里,对JVM做一些解释,-Xms和-Xmx确定了JVM中的堆的大小为15M,-XX:NewRatio定义了新生代与老年代的的比例为1:2,则可以推测出新生代大小约为4M。-XX:SurvivorRatio定义了Eden与Survivor区域的比例为1:1,则可以推出Eden大小为2M,From与To约为1M。

首先,为了更好的了解程序的GC日志。

{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 3584K, used 1880K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 91% used [0x00000000ffb00000,0x00000000ffcd6060,0x00000000ffd00000)
  from space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)
  to   space 1536K, 0% used [0x00000000ffd00000,0x00000000ffd00000,0x00000000ffe80000)
 ParOldGen       total 11264K, used 0K [0x00000000ff000000, 0x00000000ffb00000, 0x00000000ffb00000)
  object space 11264K, 0% used [0x00000000ff000000,0x00000000ff000000,0x00000000ffb00000)
 Metaspace       used 2704K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 301K, capacity 386K, committed 512K, reserved 1048576K
2016-05-17T23:21:12.248+0800: 0.268: [GC (Allocation Failure) [PSYoungGen: 1880K->1212K(3584K)] 1880K->1220K(14848K), 0.0025642 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 3584K, used 1212K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 0% used [0x00000000ffb00000,0x00000000ffb00000,0x00000000ffd00000)
  from space 1536K, 78% used [0x00000000ffd00000,0x00000000ffe2f060,0x00000000ffe80000)
  to   space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)
 ParOldGen       total 11264K, used 8K [0x00000000ff000000, 0x00000000ffb00000, 0x00000000ffb00000)
  object space 11264K, 0% used [0x00000000ff000000,0x00000000ff002000,0x00000000ffb00000)
 Metaspace       used 2704K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 301K, capacity 386K, committed 512K, reserved 1048576K
}

       由GC前,堆的日志可以看出,在发生第一次Minor GC时,PSYoungGen区域大小为3584K(约为3.5M),其中1880K(约为1.8M),这主要是Eden中的对象的大小。从详细内容来看,只有Eden区域利用率达到了91%即1880K。此时From和To、以及老年代利用率都是0%。此时,是由于Eden区域内存已满,无法在为我们的对象分配内存而引发的。

       通过GC日志可以看出YGC前新生代占用大小为1880K(约1.8M),YGC后新生代占用内存大小为1212K,约为1.2M,而PSYoungGen总大小为3584K(约为3.5M)。YGC前JVM堆内存占用为1881K(约1.8M),YGC后堆内存占用为1220K(约1.2M),JVM对总大小为14848K(约为15M)。

       由GC后,堆的日志日志信息可以看出,此时Eden区和To区域已经被清空了。而From区域则存放所有在Minor GC后仍存活的对象(大小约为1212K)。这里虽然是From区域,就向前面讲解的一样,这是在GC后进过交换From与To区域,使得预留在新生代的对象被存放到了From区域。

       这一小节,我们通过案例深入的了解了对象在Minor GC时,对象会先预留在新生代,

并对Minor GC过程做了讲解。为读者深入了解JVM GC过程奠定了基础。

版权声明:本文为博主原创文章,转载时请标明出处。

JVM 实用参数-5 新生代垃圾回收

本部分,我们将关注堆(heap) 中一个主要区域,新生代(young generation)。首先我们会讨论为什么调整新生代的参数会对应用的性能如此重要,接着我们将学习新生代相关的JVM参数。 ...
  • xiaolang85
  • xiaolang85
  • 2016年07月26日 15:43
  • 484

根据应用程序设置JVM参数(二)-优化新生代大小

一、 还是接着上一篇的讲: 继续贴上一次运行的日志数据 分析: 1.看频率,可以发现基本上是4秒进行一次Gc 2.看耗时,可以发现基本上是需要0.037秒 当前的虚拟机...
  • q291611265
  • q291611265
  • 2015年08月28日 14:22
  • 2486

jvm java虚拟机 新生代的配置

1.1.1.1. -Xmn参数 参数-Xmn1m可以用于设置新生代的大小。设置一个较大的新生代会影响老生代的大小,因为这两者的总和是一定的,这个系统参数对于系统性能以及GC行为有很大的影响,新生代一般...
  • qq_30739519
  • qq_30739519
  • 2016年04月04日 10:31
  • 15522

新生代垃圾回收

之前的两篇文章(java运行时数据区浅析、java垃圾收集器(GC)浅析)介绍了java运行时数据区以及GC垃圾回收算法的相关知识,大家可以先去看看这两篇文章。 本篇文章将重点关注新生代的垃圾回...
  • RowandJJ
  • RowandJJ
  • 2014年06月16日 09:24
  • 2008

JVM的GC机制<一>新生代GC

JVM的GC机制面试后有空再写。做好一件事不容易。 Ref: 官方gc collector说明:http://www.oracle.com/webfolder/technetwork/tu...
  • wuqiuping695
  • wuqiuping695
  • 2015年05月03日 11:29
  • 976

JVM内存管理、JVM垃圾回收机制、新生代、老年代以及永久代

你对JVM内存组成结构和JVM垃圾回收机制是否熟悉,这里和大家简单分享一下,希望对你的学习有所帮助,首先来看一下JVM内存结构,它是由堆、栈、本地方法栈、方法区等部分组成,结构图如下所示。 JV...
  • zhb123GGGGGG
  • zhb123GGGGGG
  • 2014年11月07日 22:18
  • 14535

在JVM中,新生代和旧生代有何区别?GC的回收方式有几种?server和client有和区别?

一.概述 java的最大好处是自动垃圾回收,这样就无需我们手动的释放对象空间了,但是也产生了相应的负效果,gc是需要时间和资源的,不好的gc会严重影响系统的系能,因此良好的gc是JVM的高性能的...
  • developerFBI
  • developerFBI
  • 2014年04月12日 12:09
  • 7916

对JVM中垃圾回收机制的个人理解--新生代,老年代,永久代

就想通过这个方式看看自己看完一遍书后还记得什么... 不管怎么样要先来个帅气的开场白:有错的地方请多指正,3q!!!!!!!!!!!!!!!!!!!!!!! 在堆中,新生代主要存放的是哪些很快就会被G...
  • qq_28750155
  • qq_28750155
  • 2016年01月25日 13:41
  • 6035

JVM--堆的新年代和老年代

Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。 在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Yo...
  • oChangWen
  • oChangWen
  • 2016年05月14日 17:41
  • 3143

JVM垃圾收集算法(复制算法)----关于 新生代老年代

转:http://www.cnblogs.com/E-star/p/5556188.html 1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可...
  • zp357252539
  • zp357252539
  • 2016年08月13日 09:44
  • 1310
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JVM中将对象预留在新生代
举报原因:
原因补充:

(最多只允许输入30个字)