`
liuzhaodong89
  • 浏览: 59825 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

jvm对大对象分配内存的特殊处理

    博客分类:
  • jvm
阅读更多

    前段日子在和leader交流技术的时候,偶然听到jvm在分配内存空间给大对象时,如果young区空间不足会直接在old区切一块过去。对于这个结论很好奇,也比较怀疑,所以就上网搜了下,发现还真有这么回事。以下给出具体代码来说明:

首先定义好jvm内存各个区域的大小。我设定的是eden区8M,from和to各1M,old区10M,总共20M的空间,参数如下:

-Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8

    紧接着,开始写程序。很简单,就是初始化一个9M的程序,然后用jstat命令看jdk的内存使用情况。

public class App {
	private static final int _1MB = 1024 * 1024;

	/**
	 * VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
	 * -XX:PretenureSizeThreshold=3145728
	 */
	public static void main(String[] args) {
		byte[] allocation = new byte[9*_1MB];
		while(true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

    然后打成jar,执行。结果如下:

S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT   
  0.00   0.00  18.04  90.00  23.08      0    0.000    20    0.027    0.027

    果然,当对象大小大于eden区的时候会直接扔到old区。但我还不满足与此,于是将对象改大了些,改成了11M。再次尝试发现结果如下:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.taobao.jdkmem.App.main(App.java:17)

    到这里结束了么?当然没有:)这个是一个大的完整的对象,当大对象本身是由一连串的小对象组成的时候,会不会不再OOM呢?于是改了代码再次尝试:

public class App {
	private static final int _1MB = 1024 * 1024;

	/**
	 * VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
	 * -XX:PretenureSizeThreshold=3145728
	 */
	public static void main(String[] args) {
		byte[][] allocation;
		allocation = new byte[11][_1MB]; // 直接分配在老年代中
		while(true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

    再次运行,结果如下:

S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT   
  0.00  38.06  67.68  60.02  23.10      1    0.007    14    0.012    0.019

    果然,这次居然又被jvm给生吃下去了。不过这次并非所有的都在old区,而是有一部分还在young区里活着。看来jvm还是足够彪悍的。

    由此可见,当出现大对象的时候,jvm用牺牲部分宝贵的old区的方式来保证了整个jvm的正常运转。所以,程序中尽量要避免大对象,如果实在不行,就让大对象活的尽量久些,莫要new一个然后gc掉再new一个再gc,这么爆jvm可不太友好。

    到这里结束了吧?你猜对了,还没有:P既然知道jvm会对大对象申请内存做特殊处理,那么就在琢磨程序员有没有方法干预这个过程呢?答案是有的,就是使用这个参数-XX:PretenureSizeThreshold。这个参数的单位是Byte,其作用是当新对象申请的内存空间大于这个参数值的时候,直接扔到old区。做个试验就证明了:

public class App {
	private static final int _1MB = 1024 * 1024;

	/**
	 * VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
	 * -XX:PretenureSizeThreshold=3145728
	 */
	public static void main(String[] args) {
		byte[] allocation = new byte[4*_1MB];
		while(true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

    运行命令如下:

java -jar -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728 memtest-1.0-SNAPSHOT.jar 

    我设置的阈值是3M,意味着超过3M的对象会被直接扔到old区。结果是皆大欢喜,新对象直接被扔到了old区:

S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT   
  0.00   0.00  18.04  40.00  23.08      0    0.000     0    0.000    0.000
    试验有了结果,自然而然心情愉悦。但这个参数使用时需要慎重,因为fullgc的代价很高,因此old区就显得非常宝贵。除非你真的清楚你在干什么,否则莫要轻易玩这个参数,万一搞个频繁fullgc就玩大了。ok,到此打完收工。

 

 

9
13
分享到:
评论
11 楼 wenxin45445 2017-03-13  
最近也在学习jvm,对上面说的一条规则是大对象直接进入老年代,测试了一下,jdk6和7好像还不太相同,请问一下,这个大对象究竟多大算大对象?6和7有区别吗?
10 楼 337240552 2012-09-10  
想不通怎么这么多人踩呢。。。。期待踩的人写出更好的
9 楼 liuzhaodong89 2012-08-31  
bhdweb 写道
博主请问是怎么看到这些的

S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT  
  0.00   0.00  18.04  90.00  23.08      0    0.000    20    0.027    0.027

我也想去试试。。可不知道怎么看

用jstat命令,这个是jvm自带的命令,可以到网上google一下用法的
8 楼 lection.yu 2012-08-31  
高人。jvm了解到深入许多。不过我是从来遇到过一次创建这么大对象的场景
7 楼 bhdweb 2012-08-31  
博主请问是怎么看到这些的

S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT  
  0.00   0.00  18.04  90.00  23.08      0    0.000    20    0.027    0.027

我也想去试试。。可不知道怎么看
6 楼 songbin0201 2012-08-31  
嗯,学习了,一次不错的尝试和总结过程
5 楼 w156445045 2012-08-31  
看不懂写的啥~
4 楼 magicyang919 2012-08-31  
牛xx人啊
3 楼 337240552 2012-08-31  
2 楼 saturn 2012-08-31  
1 楼 7454103 2012-08-31  
nice 

相关推荐

    resin-jvm 调优

    gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。java语言并不要求jvm有gc,也没有规定gc如何工作。不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作。 在充分理解了...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    / 66 3.5.2 大对象直接进入老年代 / 68 3.5.3 长期存活的对象将进入老年代 / 69 3.5.4 动态对象年龄判定 / 71 3.5.5 空间分配担保 / 73 3.6 本章小结 / 75 第4章 虚拟机性能监控与故障处理工具 / 76 4.1 概述...

    java核心面试

    每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些对象成员变量的拷贝,线程对所有对象成员变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。...

    java核心面试技术点

    每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些对象成员变量的拷贝,线程对所有对象成员变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。...

    Java虚拟机

    全书共分为五大部分,围绕内存管理、执行子系统、程序编译与优化、高效并发等核心主题对JVM进行了全面而深入的分析,深刻揭示了JVM的工作原理。第一部分从宏观的角度介绍了整个Java技术体系、Java和JVM的发展历程、...

    超级有影响力霸气的Java面试题大全文档

    内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的...

    net学习笔记及其他代码应用

    答:string str = null 是不给他分配内存空间,而string str = \"\" 给它分配长度为空字符串的内存空间。 25.请详述在dotnet中类(class)与结构(struct)的异同? 答:Class可以被实例化,属于引用类型,是分配在内存的...

    疯狂JAVA讲义

    学生提问:能不能只分配内存空间,不赋初始值呢?89 4.5.4 使用数组 90 学生提问:为什么要我记住这些异常信息? 91 4.5.5 JDK1.5提供了foreach循环 91 4.6 深入数组 93 4.6.1 内存中的数组 93 学生提问:为...

    java 面试题 总结

    内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的...

    JAVA上百实例源码以及开源项目

     关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用私钥对信息(info)签名,用指定算法产生签名对象,用私钥初始化签名对象,将待签名的数据传送给签名对象(须在初始化之后),用公钥...

    JAVA上百实例源码以及开源项目源代码

    关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用私钥对信息(info)签名,用指定算法产生签名对象,用私钥初始化签名对象,将待签名的数据传送给签名对象(须在初始化之后),用公钥...

    java开源包1

    利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类...

    java开源包11

    利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类...

    java开源包2

    利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类...

    java开源包3

    利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类...

    java开源包6

    利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类...

    java开源包5

    利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类...

    java开源包10

    利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类...

Global site tag (gtag.js) - Google Analytics