----------~开篇分享一句话:【纸上得来终觉浅,绝知此事要躬行】~---------------------------------------
实战分析:
http://wangxinchun.iteye.com/blog/2190330
http://www.360doc.com/content/14/0508/18/11965070_375867925.shtml
http://www.cnblogs.com/dingyingsi/p/3760447.html
jvm的组成:
java内存组成:堆(Heap)和非堆(Non-heap)内存
按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给 自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中。
jvm 内存的构成:
方法栈&本地方法栈:线程创建时产生,方法执行时生成栈帧
永久代(方法区):存储类的元数据信息 常量等
堆(heap):java代码中所有的new操作
native Memory(C heap)
Direct Bytebuffer JNI Compile GC;
JVM体系结构
JVM运行时数据区
共享内存区
JVM运行时内存 = 共享内存区 + 线程内存区
共享内存区 = 持久带 + 堆
持久带 = 方法区 + 其他
堆 = Old Space + Young Space
Young Space = Eden + S0 + S1
堆内存分配:
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指 定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。
Young Generation:Eden + From Space + To Space
Eden:存放新生的对象
Survivor Space:有两个,存放每次垃圾回收后存活的对象
Old Generation:主要存放应用程序中生命周期长的存活对象
非堆内存分配:
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
Permanent Generation:
1、保存虚拟机自己的静态(refective)数据
2、主要存放加载的Class类级别静态对象如class本身,method,field等等
3、permanent generation空间不足会引发full GC
直接内存:
直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError 异常出现。应用在某些场景中能显著提高性能,因为其避免了在Java堆和Native堆中来回复制数据。
显然,本机直接内存的分配不会受到Java 堆大小的限制,但是,既然是内存,则肯定还是会受到本机总内存(包括RAM 及SWAP 区或者分页文件)的大小及处理器寻址空间的限制。服务器管理员配置虚拟机参数时,一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError异常。
Jvm Stack(java虚拟机栈):不在堆区
Local Method Statck(本地方法栈)
JVM内存限制(最大值)
32位 最大为4G,64位无限制
jvm参数:
-Xmx3550m:设置JVM最大可用内存为3550M。
-Xms3550m:设置JVM初使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2G:设置年轻代大小为2G。
-Xss1M: 设置线程堆栈的大小,和方法调用的深度以及StackOverFlowError有密切关系
XX:NewRatio=4,设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
注意:一般情况下XX:NewRatio 和 -Xmn 不同时设置
-XX:SurvivorRatio=4:设置年轻代中Eden区与一个Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代大小为16m。
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。
注意:
整个JVM内存大小=年轻代大小 + 年老代大小
年老代大小 = Xmx-Xmn
JVM 参数默认值:
-Xms 默认情况下堆内存的64分之一
-Xmx 默认情况下对内存的4分之一
-Xmn 默认情况下堆内存的64分之一
-Xss 一个线程的占用内存大小,方法调用的深度
-XX:NewRatio 默认为2
-XX:SurvivorRatio 默认为8
-XX:-OmitStackTraceInFastThrow :始终打印 异常错误信息,否则:很多行的java.lang.NullPointerException 苦于找不到stacktrace而不知道错误出在何处。
-XX:+DisableExplicitGC:这个参数作用是禁止代码中显示调用GC。代码如何显示调用GC呢,通过System.gc()函数调用。如果加上了这个JVM启动参数,那么代码中调用System.gc()没有任何效果,相当于是没有这行代码一样。
-verbose:gc: -XX:+PrintGC 与 -verbose:gc 是一样的,可以认为-verbose:gc 是 -XX:+PrintGC的别名.
参数-XX:+PrintGC(或者-verbose:gc)开启了简单GC日志模式,为每一次新生代(young generation)的GC和每一次的Full GC打印一行信息。下面举例说明:
[GC 246656K->243120K(376320K), 0.0929090 secs]
[Full GC 243120K->241951K(629760K), 1.5589690 secs]
简
单模式的GC日志格式是与GC算法无关的,日志也没有提供太多的信息。在上面的例子中,我们甚至无法从日志中判断是否GC将一些对象从young generation移到了old generation。所以详细模式的GC日志更有用一些。
-XX:+PrintGCDateStamps: -XX:+PrintGCTimeStamps,这个选项记录的是jvm启动时间为起点的相对时间,可读性较差,不利于定位问题,使用PrintGCDateStamps记录的是系统时间,更humanreadable
-XX:+PrintGCDetails :打印gc日志的详细信息
[GC [PSYoungGen: 142816K->10752K(142848K)] 246648K->243136K(375296K), 0.0935090 secs]
[Times: user=0.55 sys=0.10, real=0.09 secs]
这是一次在young generation中的GC,它将已使用的堆空间从246648K减少到了243136K,用时0.0935090秒。此外我们还可以得到更多的信息:所使用的垃圾收集器(即PSYoungGen)、young generation的大小和使用情况(在这个例子中“PSYoungGen”垃圾收集器将young generation所使用的堆空间从142816K减少到10752K)。
既然我们已经知道了young generation的大小,所以很容易判定发生了GC,因为young generation无法分配更多的对象空间:已经使用了142848K中的142816K。我们可以进一步得出结论,多数从young generation移除的对象仍然在堆空间中,只是被移到了old generation:通过对比绿色的和蓝色的部分可以发现即使young generation几乎被完全清空(从142816K减少到10752K),但是所占用的堆空间仍然基本相同(从246648K到243136K)。
详细日志的“Times”部分包含了GC所使用的CPU时间信息,分别为操作系统的用户空间和系统空间所使用的时间。同时,它显示了GC运行的“真实”时间(0.09秒是0.0929090秒的近似值)。如果CPU时间(译者注:0.55秒+0.10秒)明显多于”真实“时间(译者注:0.09秒),我们可以得出结论:GC使用了多线程运行。这样的话CPU时间就是所有GC线程所花费的CPU时间的总和。实际上我们的例子中的垃圾收集器使用了8个线程。
-Xloggc: /home/qddd/www/ddd/logs/gc.log: 指定gd日志打印的位置
-XX:+HeapDumpOnOutOfMemoryError:可以在内存的溢出的时候,输出hprof文件
并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序继续运行,而垃圾收集程序运行于另一个CPU上。
GC的时机:
YGC:eden空间不足
FGC:
1、old空间不足
2、perm空间不足
3、显示调用System.gc() ,包括RMI等的定时触发
-----------------------------------------------------------------------------------
内存模型:http://www.cnblogs.com/redcreen/archive/2011/05/04/2036387.html
调优:http://unixboy.iteye.com/blog/174173
参数设置:http://www.jvmer.com/jvm-xx-%E5%8F%82%E6%95%B0%E4%BB%8B%E7%BB%8D/
垃圾回收器:http://www.cnblogs.com/redcreen/archive/2011/05/04/2037029.html
内存申请步骤:http://www.cnblogs.com/redcreen/archive/2011/05/04/2037056.html