JVM内存机制资料笔记
参考
3/26/2013
第1页,共6页Page 1 , Total6
JDK5.0垃圾收集优化之--Don't Pause
http://blog.csdn.net/calvinxiu/archive/2007/05/18/1614473.aspx JVM内存模型以及垃圾回收
http://hi.baidu.com/xuwanbest/blog/item/0587d82f2c44a73d1e30892e.html 对jvm内存的一些理解
http://www.blogjava.net/midstr/archive/2008/09/21/230292.html 了解JVM的内存管理与垃圾回收
http://hi.baidu.com/jiaozhenqing/blog/item/f18b85d4c1063a07a08bb77e.html Java内存溢出的解决方案
http://hi.baidu.com/yanghlcn/blog/item/029e7303917b528dd43f7cc3.html
Java内存组成
堆(Heap)
运行时数据区域,所有类实例和数组的内存均从此处分配。Java 虚拟机启动时创建。对象的堆内存由称为垃圾回收器 的自动内存管理系统回收。 组成
News Generation (Young Generation即图中的Eden + From Space + To Space)
3/26/2013
第2页,共6页Page 2 , Total6
Eden 存放新生的对象
Survivor Space 两个 存放每次垃圾回收后存活的对象
Old Generation (Tenured Generation 即图中的Old Space) 主要存放应用程序中生命周期长的存活对象 非堆内存
JVM具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、
字段和方法数据,以及方法和构造方法的代码。它是在 Java 虚拟机启动时创建的。
除了方法区外,Java 虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。 例如,JIT 编译器需要内存来存储从 Java 虚拟机代码转换而来的本机代码,从而获得高性能。
组成
Permanent Generation (图中的Permanent Space) 存放JVM自己的反射对象,比如类对象和方法对象 native heap
GC策略
堆
JVM采用一种分代回收 (generational collection) 的策略,用较高的频率对年轻的对象(young generation)进行扫描和回收,这种叫做minor collection,而对老对象(old generation)的检查回收频率要低很多,称为major collection。这样就不需要每次GC都将内存中所有对象都检查一遍。
当一个URL被访问时,内存申请过程 如下:
A. JVM会试图为相关Java对象在Eden中初始化一块内存区域 B. 当Eden空间足够时,内存申请结束。否则到下一步
C. JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收), 释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区
D. Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区
E. 当OLD区空间不够时,JVM会在OLD区进行完全的垃圾收集(0级)
F. 完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”out of memory错误”
3/26/2013
第3页,共6页Page 3 , Total6
对象衰老的过程
young generation的内存,由一块Eden(伊甸园,有意思)和两块Survivor Space(1.4文档中称为semi-space)构成。新创建的对象的内存都分配自eden。两块Survivor Space总有会一块是空闲的,用作copying collection的目标空间。Minor collection的过程就是将eden和在用survivor space中的活对象copy到空闲survivor space中。所谓survivor,也就是大部分对象在伊甸园出生后,根本活不过一次GC。对象在young generation里经历了一定次数的minor collection后,年纪大了,就会被移到old generation中,称为tenuring。(是否仅当survivor space不足的时候才会将老对象tenuring? 目前资料中没有找到描述)
剩余内存空间不足会触发GC,如eden空间不够了就要进行minor collection,old generation空间不够要进行major collection,permanent generation空间不足会引发full GC。 非堆内存
GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误。
JVM的默认设置
堆 (heap)(News Generation 和Old Generaion 之和)的设置 初始分配的内存由-Xms指定,默认是物理内存的1/64但小于1G。 最大分配的内存由-Xmx指定,默认是物理内存的1/4但小于1G。 默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio=指定。
默认空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio=指定。
服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小,所以上面的两个参数没啥用。
-Xmn 设置young generation的heap大小
-XX:MinHeapFreeRatio与-XX:MaxHeapFreeRatio设定空闲内存占总内存的比例范围,这两个参数会影响GC的频率和单次GC的耗时。-XX:NewRatio决定young与old generation的比例。Young generation空间越大,minor collection频率越低,但是
3/26/2013
第4页,共6页Page 4 , Total6
old generation空间小了,又可能导致major collection频率增加。-XX:NewSize和-XX:MaxNewSize直接指定了young generation的缺省大小和最大大小。
非堆内存 的设置 默认分配为64M
-XX:PermSize设置最小分配空间,-XX:MaxPermSize设置最大分配空间。一般把这两个数值设为相同,以减少申请内存空间的时间。
内存溢出 的原 因
Old Generation溢出
这种内存溢出是最常见的情况之一,产生的原因可能是: 1) 设置的内存参数过小(ms/mx, NewSize/MaxNewSize) 解决方法:
1G内存环境下java jvm 的参数设置参考:
-server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m -Djava.awt.headless=true
2) 程序问题
单个程序持续进行消耗内存的处理,如循环几千次的字符串处理,对字符串处理应建议使用
StringBuffer。此时不会报内存溢出错,却会使系统持续垃圾收集,无法处理其它请求,相关问题程序可通过Thread Dump获取。
单个程序所申请内存过大,有的程序会申请几十乃至几百兆内存,此时JVM也会因无法申请到资源而出现内存溢出,对此首先要找到相关功能,然后交予程序员修改,要找到相关程序,必须在Apache日志中寻找。
当Java对象使用完毕后,其所引用的对象却没有销毁,使得JVM认为他还是活跃的对象而不进行回收,这样累计占用了大量内存而无法释放。由于目前市面上还没有对系统影响小的内存分析工具,故此时只能和程序员一起定位。
Permanent Generation 溢出
通常由于 Perm 段装载了大量的类而导致溢出,如 spring的动态生成类。 目前的解决办法:
3/26/2013
第5页,共6页Page 5 , Total6
1) 将 Perm Size扩大,一般256M能够满足要求
2) 若别无选择,则只能将servlet的路径加到CLASSPATH中,但一般不建议这么处理
C Heap溢出
系统对C Heap没有限制,故C Heap发生问题时,Java进程所占内存会持续增长,直到占用所有可用系统内存
3/26/2013
第6页,共6页Page 6 , Total6
因篇幅问题不能全部显示,请点此查看更多更全内容