`
燈小嗨
  • 浏览: 14260 次
  • 性别: Icon_minigender_1
最近访客 更多访客>>
社区版块
存档分类
最新评论

JAVA内存占用情况实验

阅读更多

之前在公司听了一门关于java 内存占用方面的讲座,收获颇丰,回来后在eclipse 下进行了一些简单的尝试,但是实验遇到了一些小小的问题,通过向大牛咨询和查资料的方式逐渐将这些问题解决了,现在将我在这些实验中遇到的问题,已经解决的方法和大家分享下,希望各位指点其中的错误,谢谢!

 

Java 环境:

Java version "1.6.0_24"

Java(TM) SE Runtime Environment (build 1.6.0_24-b07)

Java HotSpot(TM) Client VM (build 19.1-b02,mixed mode, sharing) 

 

设置JVM 启动参数为 -Xms12m -Xmx12m ,然后运行如下程序:

 

public class MemTest {

	public static void main(String[] args) {
		int[] intArray = new int[2*1024*1024];
	}

}
 

程序运行后出现

 

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at thread.ThreadCount.main(ThreadCount.java:6)
 

说明程序运行时堆内存溢出。

存在疑问:

  java 中,每个int 4 字节,这个int 数组共有2*1024*1024int 类型,那我们可以推断出这个int 数据占据了大约8M ,而且这些空间是在内存堆中开辟的。现在我们已设置好内存堆有12M 的空间,也就是说除去程序其他内存堆开销整个堆内存应该剩下将近4m ,但是此处运行后,程序发生内存堆不够的内存溢出。

疑问解答:

之所以遇到上面的问题是因为我们所使用的Java HotSpot(TM) 虚拟机是一种分代式的结构,其主要结构如下所示:

HotSpot Jvm内存堆结构

此种类型的GC 堆分成了三代,分别是Young GenerationOld GenerationTenured )、Permanent Generation

其中Young GenerationEdenS0S1 (就是图上说的survivorspaces 区)组成,它主要负责存放新生成的对象,当Eden 区满时,还存活的对象被复制到S0 ,当S0 满时,复制到S1 ,当S1 满时将从S0 复制过来的且存活的对象复制到Old Generation 。其中S0S1 两个区是对称的,没有先后关系,一个S 区中可能存在着从Eden 或是另一个S 区复制过来的对象,而只有从另一个S 区复制过来的数据才能继续复制到老年区。而

Old Generation 区中存放的从Young 区复制来的存活对象,都是生命周期较长的对象。

另外,Permanent Generation 对应着JVM 规范中的方法区,主要存放一些静态成员、常量,在HotPot VM 中可使用-XX:PermSize XX:MaxPermSize 对此区域进行调节。

在试验中新建的intArray 数组,需要连续的内存空间存储且一个对象不能跨代存储,也就是说,我们新建的对象大小不能超过了GC 堆中空间最大的一代,一般情况下,最大的代是Old Generation ,因此当intArray 数组对象为8M 时,可能已经超过了Old Generation 的大小,所以发生内存溢出异常。

了解完HotSpot 的构造后,我们来看看为什么之前的代码会发生内存溢出。这个因为在试验中新建的intArray 数组,需要连续的内存空间存储且一个对象不能跨代存储,也就是说,我们新建的对象大小不能超过了GC 堆中空间最大的一代,一般情况下,最大的代是Old Generation ,因此当intArray 数组对象为8M 时,已经超过了Old Generation 的大小,所以发生内存溢出异常。

 

  • 大小: 23.6 KB
2
12
分享到:
评论
10 楼 燈小嗨 2011-10-10  
newjavaconte12 写道
到底谁是对的啊


对象只能存放于young或old两代中,是不能跨代存储的,perm是存放类的静态变量等东西,就是jvm规范中提到的方法区,不存放对象。
9 楼 newjavaconte12 2011-10-09  
到底谁是对的啊
8 楼 langyu 2011-10-03  
燈小嗨 写道
那你的意思是,对象可以跨代存储了?

堆内容有三个代,我们创建的对象只能存放于young或old,而不能跑到perm区。
7 楼 燈小嗨 2011-10-03  
langyu 写道
引用
也就是说,我们新建的对象大小不能超过了GC 堆中空间最大的一代

你听谁这样说的?



那你的意思是,对象可以跨代存储了?
6 楼 燈小嗨 2011-10-03  
1927105 写道
推荐lz看一本分布式应用一书,里面挺有用的。


能推荐一本不?
5 楼 燈小嗨 2011-10-03  
zhouguiping2008 写道


当这个tenured代超过70%就会执行又一次全垃圾收集,回收之后还在70%以上也可能抛出内存溢出



恩,加上参数XX:NewRatio=4,同时查看heap内存变化验证了你的说法。

但我有疑问的是,这个触发FGC的阈值是根据不同垃圾收集器来定的吧?70%应该不一定吧?
4 楼 zhouguiping2008 2011-10-03  
分析的有点强求,

其实溢出的原理是这样的,你分配了12M的堆内存,但是没有指定各个代的分配策略,也就是采用jvm的默认分配策略,-XX:SurvivorRatio=8,-XX:NewRatio=2,老年代和年轻代的比例是2,这个时候young分配的空间是4M空间,tenured分了8M,每个survivor代分了0.4M,eden分了3.2M,你实例化了一个8M大小的对象,由于eden代没有这么大的空间来存放这个对象,所以直接把这个对象分配到tenured代中,而这个代中总共也只有8M,当然会抛出内存溢出啊,而且当这个tenured代超过70%就会执行又一次全垃圾收集,回收之后还在70%以上也可能抛出内存溢出。如果你手动设置参数-XX:NewRatio=4就不会内存溢出了,现在知道了原因了吧。
3 楼 1927105 2011-10-03  
推荐lz看一本分布式应用一书,里面挺有用的。
2 楼 1927105 2011-10-03  
langyu 写道
引用
也就是说,我们新建的对象大小不能超过了GC 堆中空间最大的一代

你听谁这样说的?


难道是剩余的堆栈空间?
1 楼 langyu 2011-10-03  
引用
也就是说,我们新建的对象大小不能超过了GC 堆中空间最大的一代

你听谁这样说的?

相关推荐

Global site tag (gtag.js) - Google Analytics