读书人

Java的内存储器结构(Memory Structure

发布时间: 2012-09-05 15:19:35 作者: rapoo

Java的内存结构(Memory Structure)和垃圾收集(Garbage Collection)图解

?

原文地址:http://blog.csdn.net/autofei/article/details/7456213

?

前段时间在一个项目的性能测试中又发生了一次OOM(Out of swap sapce),情形和以前网店版的那次差不多,比上次更奇怪的是,此次搞了几天之后啥都没调整系统就自动好了,死活没法再重现之前的OOM了!问题虽然蹊跷,但也趁此机会再次对JVM堆模型、GC垃圾算法等进行了一次系统梳理;

基本概念

堆/Heap

JVM管理的内存叫堆;在32Bit操作系统上有4G的限制,一般来说Windows下为2G,而Linux下为3G;64Bit的就没有这个限制。
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64但小于1G。
JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4但小于1G。
默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio=指定。?
默认空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio=指定。
服务器一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小,所以上面的两个参数没啥用。

分代/堆模型

分代是Java垃圾收集的一大亮点,根据对象的生命周期长短,把堆分为3个代:Young,Old和Permanent,根据不同代的特点采用不同的收集算法,可以扬长避短。可参考如下的模型图:Java的内存储器结构(Memory Structure)和垃圾收集(Garbage Collection)图解

Young(Nursery):年轻代

研究表明大部分对象都是朝生暮死,随生随灭的。所以对于年轻代在GC时都采取复制收集算法,具体算法参考下面的描述;
Young的默认值为4M,随堆内存增大,约为1/15,JVM会根据情况动态管理其大小变化。
Young里面又分为3个区域,一个Eden,所有新建对象都会存在于该区,两个Survivor区,用来实施复制算法。
-XX:NewRatio= 参数可以设置Young与Old的大小比例,-server时默认为1:2,但实际上young启动时远低于这个比率?如果信不过JVM,也可以用-Xmn硬性规定其大小,有文档推荐设为Heap总大小的1/4。
-XX:SurvivorRatio= 参数可以设置Eden与Survivor的比例,默认为32。Survivio大了会浪费,小了的话,会使一些年轻对象潜逃到老人区,引起老人区的不安,但这个参数对性能并不太重要。

Old(Tenured):年老代

年轻代的对象如果能够挺过数次收集,就会进入老人区。老人区使用标记整理算法。因为老人区的对象都没那么容易死的,采用复制算法就要反复的复制对象,很不合算,只好采用标记清理算法,但标记清理算法其实也不轻松,每次都要遍历区域内所有对象,所以还是没有免费的午餐啊。
-XX:MaxTenuringThreshold= 设置熬过年轻代多少次收集后移入老人区,CMS中默认为0,熬过第一次GC就转入,可以用-XX:+PrintTenuringDistribution查看。

Permanent:持久代

装载Class信息等基础数据,默认64M,如果是类很多很多的服务程序,需要加大其设置-XX:MaxPermSize=,否则它满了之后会引起fullgc()或Out of Memory。 注意Spring,Hibernate这类喜欢AOP动态生成类的框架需要更多的持久代内存。一般情况下,持久代是不会进行GC的,除非通过-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled进行强制设置。

GC的类型

当每个代满了之后都会自动促发collection,各收集器触发的条件不一样,当然也可以通过一些参数进行强制设定。主要分为两种类型:

读书人网 >编程

热点推荐