`

jvm之调优理论篇

阅读更多

----------~开篇分享一句话:【纸上得来终觉浅,绝知此事要躬行】~--------------------------------------- 

实战分析: 
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

  • 大小: 27.6 KB
  • 大小: 22.4 KB
  • 大小: 8.4 KB
  • 大小: 8.3 KB
1
0
分享到:
评论
3 楼 王新春 2015-03-07  
61308519 写道
理论倒处都是,有没有有点质量的实战篇

http://wangxinchun.iteye.com/blog/2190330
看看这篇能否满足你的部分需求,一起学习吧
2 楼 string2020 2015-03-06  
jdk1.8如何分配perm空间
1 楼 61308519 2015-03-06  
理论倒处都是,有没有有点质量的实战篇

相关推荐

Global site tag (gtag.js) - Google Analytics