1 堆:存放数据
栈:存放逻辑
2 虚拟机: 栈溢出,则栈大小设置-Xss 默认值为1M 但一般会不到200k,所以会将默认值调整小点
Java虚拟机本身:-Xms,-Xmx,-Xss;
系统限制:
/proc/sys/kernel/pid_max,
/proc/sys/kernel/thread-max,
max_user_process(ulimit -u),
/proc/sys/vm/max_map_count。
3 堆内存溢出
强引用内存泄露:new 出来的对象是基本上是强引用,这种引用申请不到内存,则内存泄露 。
强引用环境,垃圾回收时需要严格判断当前对象是否被强引用,如果被强引用则不会被回收。
软引用:当做缓存来用(内存受限的时候用,否则用强引用更好),当垃圾回收时候,如果内存紧张则软引用会被回收,否则不回收。
弱引用(与软引用类似):申请不到内存则会进行内存回收,不会有内存泄露
4 垃圾回收算法:
1 引用为0
2 标记清楚,它会遍历整个堆来标记无用的对象, ()
3 复制回收
四个区: e,s0,s1 ,old ,每次回收后剩下的对象会向后面的区转移 ,前三个为新生代,old为老年代
4 标记整理:
5 出发回收:
1) Scavenge: e区申请空间失败(即满了),则出发此回收
2)full GC:比较慢,尽量减少这种GC使用,一下会产生这种GC
年老带写满、持久带写满、System.gc、上一次GC后Heap各个区域分配策略动态变化
6 配置垃圾回收器
串行垃圾回收器:数量比较小,100M左右,一般单处理器对响应时间无要求 : -XX:+UseSerialGC
并行垃圾回收: 特点:,但吞吐量高。适合, 多核多处理器,响应时间无要求的中大型应用:-XX:+UseParallelOldGC , -XX:ParalleGCThreads 并行线程数量
最大暂停时间:-XX:MaxGCPauseMills=N ,如后台处理,科学计算
吞吐量:-XX:GCTimeRatio=N
并发处理器:“响应时间高要求”多cpu,对响应时间有较高要求的中大型应用,如web服务器,应用服务器,集成开发环境
7 常见配置汇总:
堆设置:
-Xms:初始堆大小 <4G
-Xmx:最大堆大小 <4G
-XX:NewSize=n:设置年轻带大小
-XX:NewRatio=n设置年轻带和年老带的比值。如为3,则年轻带与年老带比值为1:3
年轻带占整个年轻带年老带和的1/4
-XX:SurvivorRatio=n :年轻带中Eden区与两个Survivor区的比值。。
注意Survivor区有两个。如:3表示Eden:Survivor=3:2一个Survivor区占整个年轻带的1/5
-XX:MaxPermSize=n 设置持久代大小
收集器设置:
-XX:+UseSeralGC 设置串行收集器
-XX:+UseParallelGC 设置并行收集器
-XX:+UseParalledlOldGC 设置并行年老带收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息:打印垃圾回收信息,以便查看参数设置是否正确
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置:
-XX:ParallelGCThreads=n :设置并行收集器收集时使用的CPU数,并行线程数。
-XX:MaxGCPauseMillis=n: 设置并行收集最大暂停时间
-XX:GCTimeRatio=n 设置垃圾回收时间占程序运行时间的百分比:公式1/1+n
并发收集器设置:
-XX:+CMSIncrementalMode 设置为增量模式 适用单CPU
-XX:ParallelGCThreads=n 设置并发收集器年轻带收集方式为并行收集器,使用CPU
数。并行收集器线程数
JVM中最大堆大小的三方面限制:相关操作系统数据模型限制(32还是64位);系统可用虚拟内存限制;
系统的可用物理内存限制。32位系统下,一般限制在1.5-2G。
64位操作系统内存无限制 。windows Server 2003系统,3.5G物理内存,
JDK5.0下测试最大设置为1478m
典型设置1:
java -Xmx3550m-Xms3550m-Xmn2g-Xss128k
-Xmx3550m: 设置JVM最大可用内存为3550M
-Xms3550m:设置JVM初始内存为3550M。这个值设置与-Xmx形同,以避免每次
垃圾回收后JVM重新分配内存。
-Xmn2g:设置年轻带大小为2G。整个堆大小=年轻代+年老代大小+持久代大小。
持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。
此值对系统性能影响较大,Sun官方推荐为整个堆大小3/8.
-Xss128k:设置每个线程堆栈大小。以后每个线程堆栈大小为1M,以前每个线程
堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,
减小这个值能生成更多的线程。但操作系统对一个进程内的线程数还是有限制的,
不能无限制生成,经验值为3000-5000左右。
典型设置2:
java-Xmx3550m-Xms3550m-Xss128k-XX:NewRatio=4-XX:SurvivorRatio=4
-XX:MaxPermSize=16m-XX:MaxTenuringThreShold=0
-XX:newRatio=4 :设置年轻带(包括Eden和两个S区)与年老带的比值(除去持久代)
设置为4,则年轻带与年老代所占比值为1:4,年轻带占整个堆栈的1/5.
-XX:SurvivorRatio=4 :设置年轻代中Eden与Survivor区的大小比值。设置为4,则两个Survivor区
与一个Eden区的比值为2:4,一个Survivor区占整个年轻带的1/6
-XX:MaxPermSize=16m :设置持久代大小为16m
-XX:
MaxTenuringThreshold=0 设置垃圾最大年龄。如果设置为0,则年轻带对象不经Survivor区,直接
进入年老代。对于年老代比较多的应用可以提高效率,如果将此值设置为一个较大的值,则
年轻代对象会在S区进行多次复制,则会增加对象年轻代存活时间.
8 回收器选择:
JVM给了三种回收器:串行收集器,并行收集器,并发收集器
默认JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在启动时候加入相应参数。
jdk5.0以后JVM会根据当前系统配置
吞吐量优先的并行收集器:
并行收集器主要是以达到一定吞吐量为目标,适用科学技术和后台处理器:
典型配置:
java-Xmx3800m-Xms3800m-Xmn2g-Xss128k-XX:+UseParallelGC
-XX:ParallelGCThreads=20
-XX:+UseParalelGC:选择垃圾收集器为并行收集器。此配置对年轻代有效。
即上述配置下,年轻代适用并发收集,而年老带仍旧适用串行收集。
-XX:ParallelGCThreads=20: 配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。
此值最好配置与处理器数目相等。
java-Xmx3550m-Xms3550m-Xmn2g-Xss128k-XX:+UseParallelGC
-XX:ParallelGCThreads=20-XX:+UseParallelOldGC
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0
支持对年老代并行收集。
java-Xmx3550m-Xms3550m-Xmn2g-Xss128k-XX:+UseParallelGC
-XX:MaxGCPauseMillis=100
-XX:MaxGCPauseMillis=100 设置年轻代垃圾回收的最长时间,如果
无法满足此时间,JVM会自动调整年轻代大小,以满足此值。
java-Xmx3550m-Xms3550m-Xmn2g-Xss128k-XX:+UseParallelGC
-XX:MaxGCPauseMillis=100-XX:+UseAdaptiveSizePolicy
-XX:+UseAdaptiveSizePolicy 设置此选项,并行收集器会自动选择年轻代区大小
和相应的Survivor区的比例,以达到目标系统规定的最低响应时间或者
收集频率,建议使用并行收集器时,一直打开。
响应时间优先并发收集器:主要保证系统响应时间,减小垃圾手机时的
停顿时间,适用于应用服务器,电信领域等。
java-Xmx3550m-Xms3550m-Xmn2g-Xss128k-XX:+UseParallelGCThreads=20
-XX:+UseConcMarkSweepGC-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC设置年老代并发收集,测试中配置这个后,
-XX:NewRatio=4的配置失效了。所以此时配置年轻带最好用-Xmn设置。
-XX:+UseParNewGC 设置年轻带为并行收集。可以与CMS收集同时使用。
JDK5.0以后自动设置,所以无需设置。
java-Xmx3550m-Xms3550m-Xmn2g-Xss128k-XX:UseConcMakSweepGC
-XX:CMSFullGCsBeforeCompaction=5-XX:UseCMSCoimpactAtFullCollection
-XX:UseCMSCoimpactAtFullCollection :由于并发收集器不对内存空间进行空间压缩、整理,所以运行
一段时间后会产生碎片,使得运行效率降低。此值运行多少次GC后对
内存空间进行压缩,整理。
-XX:UseCMSCoimpactAtFullCollection :打开对年老带的压缩。可能会影响性能,但会产生碎片
总结:
年轻代大小选择
响应时间优先的应用:尽可能设置大,直到接近系统的最低响应时间限制
在此种情况下,年轻代收集发生的频率也是最小的。同时,较少到达年老代对象。
吞吐量优先应用:尽可能的设置大,可能达到Gbit的程度,对响应时间没有要求
垃圾收集器可以并行进行,一般适合8CPU以上的应用。
年老代大小选择:
响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等
参数。如设置小了,可能会造成碎片,高回收频率以及应用暂停而使用传统的标记清楚方式;如果堆大了,则需要较长的
收集时间,最优方案需要参考下面数值:
1)并发垃圾收集信息 2)持久代并发收集次数 3)传统GC信息 4)花在年轻代和年老代回收上的时间比例减少年轻代和
年老代花费时间,一般会提高应用效率。
吞吐量优先的应用
一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代,因为这可以尽可能
回收掉大部分短期对象,减少中期对象,而年老代尽量存放长期存活对象。
较小堆引起碎片:
-XX:UseCMSCoimpactAtFullCollection 并发收集器,开启年老代压缩
-XX:CMSFullGCsBeforeCompaction=0 : 设置多少次Full GC后对年老代压缩
9 调优方法与工具
JVM调优工具: Jconsole ,jProfile ,VisualVM
Jconsole:jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用,对垃圾回收算法
有很详细的跟踪
JProfiler: 商业软件,付费功能强大
VisualVM :JDK自带,功能强大,与JProfiler类似推荐使用。
10 内存泄露检查
内存泄露一般是资源使用完毕后无法回收,从而导致新资源请求分配无法回收。
当访问没量不大,但是对使用一直在增长,一般是内存泄露了
解决:GMap打印无法回收的对象。
堆栈溢出:StackOverflowError ,一般递归或者循环造成
线程堆栈满:Stack size too small