(1)程序计数器
看作当前线程所执行的字节码行号显示器;任意时刻,一个CPU都会执行一条线程中的指令,为了线程切换后能回到正确位置,每一个线程都须要一个独立的线程计数器;执行native方法时,计数器值为空;此区域没有任何OutOfMemoryError的区域;html
(2)虚拟机栈
虚拟机栈的生命周期和线程同步,虚拟机栈中的局部变量表用于存储各类基本数据类型、对象引用类型;long和double会占用两个局部变量表的空间,局部变量表在编译器完成空间分配;
StackOverflowError:线程请求过多
OutOfMemoryError:若是虚拟机栈扩展时没法申请到足够内存;java
(3)本地方法栈
与虚拟机栈发挥的做用很是类似,区别是:虚拟机栈为Java方法服务的;本地方法栈是为native方法服务的;算法
(4)Java堆
存放实例对象的以及数组的;
OutOfMemoryError异常;数组
堆内存划分:tomcat
Young Generation:新生代
全部新生成的对象首先都是放在年轻代的。年轻代的目标就是尽量快速的收集掉那些生命周期短的对象。年轻代分三个区:一个Eden ['i:dən]区,两个 Survivor[sə'vaɪvə]区(通常而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor[sə'vaɪvə]区(两个中的一个),当这个 Survivor区满时,此区的存活对象将被复制到另一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的而且此时还存活的对象,将被复制年老区。多线程
Old Generation:老年代
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。所以,能够认为年老代中存放的都是一些生命周期较长的对象。并发
Perm Area:永久带
用于存放静态文件,现在Java类、方法等。jvm
(5)方法区
虚拟机加载的类信息,常量,静态变量等;
运行时常量池也是方法区的一部分:存放编译器生成的各类字面量和符号引用;
OutOfMemoryError异常;布局
(1)虚拟机执行new指令 ----> 检查指令参数是否能在常量池中定位到类的符号引用 ----> 若是没有检查到引用表明的类,则先执行类的加载过程 ----> 类加载经过后,为新生对象分配内存 ----> 分配到的内存空间初始化为零 ----> 虚拟机对对象进行设置 ----> 执行init方法,完成对象建立
(2)对象在内存中存储布局可分为3块区域:
对象头:一部分存储对象自身运行时数据,如hashCode,线程持有的锁等;一部分是类型指针,肯定对象是哪一个类的实例;
实例数据:就是程序代码中定义的各类类型字段内容;
对齐填充:没有特殊含义,仅仅起到占位符的做用;ui
Java语言中可做为GC roots的对象有:
虚拟机栈引用的对象,方法区中类的静态属性、常量引用的对象,本地方法区中Native方法引用的对象;
(1)标记-清除算法:
首先标记处全部须要回收的对象,标记完成后统一回收;执行下图所示:
主要有两个缺点:一是执行效率不高,另外一个是会产生大量不连续的内存碎片,致使再次分配较大对象时,没法获得连续的内存空间而再一次触发垃圾回收机制;
(2)复制算法:
为了解决标记-清除算法的效率问题,可使用复制算法;它将内存划分为大小相等的两块,每次使用其中一块,当一块内存使用完了,就将存活的对象复制到另外一块,而后回收已使用过的内存;
该算法在对象存活较多时,效率底下,同时内存空间浪费;适合于新生代内存;
(3)标记-整理算法:
标记全部可回收对象,它不是直接对可回收对象进行清理;而是让全部的存活对象都向一端移动,而后直接清理掉端边界之外的内存;
(4)分代收集算法:
目前商业虚拟机都采用分代收集算法。
Serial ['sɪərɪəl]
收集器ParNew [pɑː][njuː]
收集器Serial Old
收集器Parallel Old ['pærəlel]
收集器其实每一个垃圾回收器的日志是不同的,可是为了方便查看日志它们也有必定的共性,以下所示的一段 GC 日志:
33.125: [GC [DefNew: 3324k->152k(3712k),0.0025925 secs] 3324->152k(11904k),0.003168 secs] 100.667: [Full GG [Tenurend: 0k->210k(1024k),0.00149142 secs]4603k->210k(19456k), [Perm : 2999k->2999k(21248k)],0.0150007 secs] [Times:user=0.01 sys=0.00,real=0.02 secs]
Serial
收集器,它的新生代命名为Default New Generation
,因此显示"[DefNew"3324k->152k(3712k)
表示"GC前该区域已使用容量->GC后该内存区域已使用容量(该内存区域总容量)"3324->152k(11904k)
表示"GC前Java堆已使用容量->GC后Java堆已使用容量(Java堆总容量)"作GC调优须要大量的实践,耐心和对项目的分析。作GC的调优很大程度上依赖于对系统的分析,系统拥有怎样的对象以及他们的平均生命周期。举个例子,若是一个应用大可能是短生命周期的对象,那么应该确保Eden区足够大,这样能够减小Minor GC的次数。能够经过-XX:NewRatio来控制新生代和老年代的比例,好比-XX:NewRatio=3表明新生代和老年代的比例为1:3。须要注意的是,扩大新生代的大小会减小老年代的大小,这会致使Major GC执行的更频繁,而Major GC可能会形成用户线程的停顿从而下降系统吞吐量。JVM中能够用NewSize和MaxNewSize参数来指定新生代内存最小和最大值,若是两个参数值同样,那么就至关于固定了新生代的大小。
(1)Minor ['maɪnə] GC:从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC;
(2)Major['meɪdʒə] GC:是清理老年代;
(3)Full GC:是清理堆空间,包括年轻代和老年代;
参考文章:Minor GC,Major GC,Full Gc
(1) -Xms : 堆内存的初始大小,默认是物理内存的1/64
(2) -Xmx : 堆内存的最大值,默认不超过物理内存
(3) -Xmn : 年轻代堆内存大小
(4) -Xss : 栈内存大小设置
(5) -XX:PermSize : 内存永久区的初始大小
(6) -XX:MaxPermSize : 内存永久区的大小
(7) -XX:SurvivorRatio : Eden区与Survivor区的大小比值;设置成8,则两个Survivor区与一个Eden区的比值是2:8
(8) -XX:+UseAdaptiveSizePolicy : 动态调整 Java 堆内存中各个区域的大小以及即进入老年代的年龄
(1) -XX:UseParallelGC : 使用 Parallel Scavenge(年轻代并行的多线程收集器) + Serial Old(老年代单线程收集器) 收集器
(2) -XX:UseParNewGC : 使用 ParNew + Serial Old 收集器
(3) -XX:ParallelGCThreads : 并行收集的线程数
(4) -XX:UseParallelOldGC : 使用 Parallel Scavenge(年轻代并行的多线程收集器) + Parallel Old 收集器
(5) -XX:MaxGCPauseMillis : 设置GC的最大停顿时间,仅在使用 Parallel Scavenge 收集器时生效
(6) -XX:+UseConcMarkSweepGC : 使用 ParNew + CMS + Serial Old 组合收集器
(7) -XX:GCTimeRatio : GC时间占总时间的比例,默认99,即容许 1% 的GC时间。仅在使用 Parallel Scavenge 收集器时生效
(1) -XX:+DisableExplicitGC : 忽略来自程序中System.gc()方法触发的垃圾回收
(2) -XX:+PrintGCDetails : 打印GC的相信信息
(3) -XX:+PrintHeapAtGC :
(4) -XX:+PrintTenuringDistribution :
(5) -XX:+PrintGCTimeStamps : 打印GC停顿耗时
(6) -XX:+PrintGCDateStamps :
(7) -XX:+HeapDumpOnOutOfMemoryError :
(8) -XX:ErrorFile :
(9) -XX:HeapDumpPath :
-XX:CMSFullGCsBeforeCompaction=0 : cms 收集器每次进入Full GC都进行碎片整理
-XX:+UseCMSCompactAtFullCollection
-XX:CMSInitiatingOccupancyFraction=80 : cms 收集器触发比例(当空间使用了80%后就触发回收)
-XX:ReservedCodeCacheSize=128m :
-XX:InitialCodeCacheSize=128m
/export/servers/jdk1.6.0_25/bin/java -server
-Xms128M -Xmx256M -Xss256K
-XX:PermSize=32M
-XX:MaxPermSize=32M
-XX:+UseAdaptiveSizePolicy
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:GCTimeRatio=39
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps -Xloggc:/export/home/tomcat/logs/loghub.360buy.com/jcollector/gc.log
-XX:+HeapDumpOnOutOfMemoryError
-XX:ErrorFile=/export/home/tomcat/logs/loghub.360buy.com/jcollector/hs_err.log
-XX:HeapDumpPath=/export/home/tomcat/logs/loghub.360buy.com/jcollector/heap_dump.hprof -classpath
JVM_ARGS="-server -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Djava.io.tmpdir=/tmp -Djava.net.preferIPv6Addresses=false"
JVM_GC="
-XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+UseConcMarkSweepGC -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps
"
JVM_GC=$JVM_GC"
-XX:CMSFullGCsBeforeCompaction=0 -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80 "
JVM_HEAP="
-XX:SurvivorRatio=8 -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError -XX:ReservedCodeCacheSize=128m -XX:InitialCodeCacheSize=128m "
JVM_SIZE="-Xmx4g -Xms4g -Xmn1g"