深入理解--JVM详解
原文出处:https://blog.****.net/hui_yan2012/article/details/70194449
Java Virtual Mechine
About JVM
- 内存划分
-
堆内存分配
VM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指 定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。
组成 | 详解 |
---|---|
Young Generation | 即图中的Eden + Survivor (From Space + To Space) |
Eden | 存放新生的对象,也是主要对象存放位置 |
Survivor Space | 有两个,存放每次垃圾回收后存活的对象,总会存在一个为空 |
Old Generation | Tenured Generation 即图中的Old Space 主要存放应用程序中生命周期长的存活对象 |
About GC
- Java 内存区域和GC机制 比较详细的介绍了JVM的内存区域划分,以及GC机制
- 成为JavaGC专家系列
对象存活
- 引用计数
对象新增一个引用,那么计数增1. - 可达性分析
从GC roots 开始向下搜索,经历的链路成为引用链,没有被引用链关联的引用,为不可用对象。
Java中GC Roots:
- 虚拟机栈中引用的对象。
- 方法区中静态属性引用的对象。
- 方法区中常量引用的对象。
- 本地方法栈中JNI引用的对象。
GC 算法
-
Mark-Sweep 标记-清除
缺点: 效率较低;碎片化严重。
-
Copy 复制算法
缺点: 持续复制,效率低。
Mark-Compact 标记-压缩(老年代使用)
GC Collectors
-
Serial
有点古老,串行收集,在多cpu,多core的今天,已经渐渐被淘汰:
参数控制: -XX:+UseSerialGC
-
ParNew
Serial 的多线程版本,新生代并行,复制算法,老年代串行,标记-压缩算法。
参数控制: -XX:+UseParNewGC; -XX:ParallelGCThreads 线程数量。
-
Parallel Scavenge
类似ParNew,他关注的系统的吞吐量,也可以通过参数实现自适应性调节控制。新生代复制算法,老年代标记-压缩算法。
-
Parallel Old
since jdk 1.6
多线程 + 标记-整理算法
参数控制: -XX:+UseParallelOldGC
-
CMS Concurrent Mark Sweep
一种以最短停顿为目标的收集器
- 初始标记(initial mark) stop-the-world,标记gc roots 直接关联对象。
- 并发标记(concurrent mark)trace gc roots
- 重新标记(remark) stop-the-world
- 并发清除(concurrent sweep)
优点:并发收集,低停顿;
缺点:大量碎片;并发阶段;参数控制: -XX:+UseConcMarkSweepGC,-XX:+ UseCMSCompactAtFullCollection 在Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长.
-
Garbage First
空间整合,G1收集器采用标记整理算法,不会产生内存空间碎片。分配大对象时不会因为无法找到连续空间而提前触发下一次GC。
可预测停顿,这是G1的另一大优势,降低停顿时间是G1和CMS的共同关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为N毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。
内存分为多个大小相等的独立区域(Region)
-
收集步骤:
- 标记阶段,首先初始标记(Initial-Mark),这个阶段是停顿的(Stop the World Event),并且会触发一次普通Mintor GC。对应GC log:GC pause (young) (inital-mark)。
- Root Region Scanning,程序运行过程中会回收survivor区(存活到老年代),这一过程必须在young GC之前完成。
- Concurrent Marking,在整个堆中进行并发标记(和应用程序并发执行),此过程可能被young GC中断。在并发标记阶段,若发现区域对象中的所有对象都是垃圾,那个这个区域会被立即回收(图中打X)。同时,并发标记过程中,会计算每个区域的对象活性(区域中存活对象的比例)。
Remark, 再标记,会有短暂停顿(STW)。再标记阶段是用来收集 并发标记阶段 产生新的垃圾(并发阶段和应用程序一同运行);G1中采用了比CMS更快的初始快照算法:snapshot-at-the-beginning (SATB)。
Copy/Clean up,多线程清除失活对象,会有STW。G1将回收区域的存活对象拷贝到新区域,清除Remember Sets,并发清空回收区域并把它返回到空闲区域链表中。
- 复制/清除过程后。回收区域的活性对象已经被集中回收到深蓝色和深绿色区域。
About Monitor
jstat
HotSpot JVM 提供的一个监控工具,不仅提供GC操作的信息,还有提供类装载操作的信息以及运行时便已操作对的信息。
- 使用方法 -> jstat -[option] [other-option] [interval] [times] ; 【jvmId】的获取 ps -ef | grep java
- 输入参数 option
参数 | 描述 |
---|---|
gc | 输出每个堆区域的当前可用空间以及已用空间(Eden,Survivor等等),GC执行的总次数,GC操作累计所花费的时间。 |
gccapacity | 输出每个堆区域的最小空间限制(ms)/最大空间限制(mx),当前大小,每个区域之上执行GC的次数。(不输出当前已用空间以及GC执行时间)。 |
gccause | 输出-gcutil提供的信息以及最后一次执行GC的发生原因和当前所执行的GC的发生原因 |
gcnew | 输出Young的GC性能 |
gcnewcapacity | Young空间大小的统计 |
gcold | OLD 空间GC性能 |
gcoldcapacity | OLD空间大小的统计 |
gcpermcapacity | perm大小的统计 |
gcutil | 输出每个堆区域使用占比,以及gc执行的总次数和GC操作所花费的时间 |
- 输出数据介绍 :
S0/S1/E/O/P [C/U] - 对应区域的空间大小和使用量,单位KB,
YGC/FGC[-/T] - GC的统计次数、时间
NGC/OGC/PGC[/MN/MX] 对应区域当前大小/最小值/最大值
GCC/LGCC 当前/最后一次GC的原因
TT 老年化阈值,在移动向老年代之前,能够在新生代存活次数。
MTT 最大老年化阈值,同上。
-
DSS 幸存者所需要的空间大小,单位KB
其中:
C - capacity 空间大小
U - used 使用量
T - 对应GC时间other-option
-hn 展示每次输出数据的前n行。 -h3 只显示前3行。
补充JVM的一些相关知识
- <span style="font-family:'Microsoft YaHei';font-size:14px;">public class JVMTest {
- public static void main(String[] args){
- long maxMemory = Runtime.getRuntime().maxMemory();//返回Java虚拟机试图使用的最大内存量。
- Long totalMemory = Runtime. getRuntime().totalMemory();//返回Java虚拟机中的内存总量。
- System.out.println("MAX_MEMORY ="+maxMemory +"(字节)、"+(maxMemory/(double)1024/1024) + "MB");
- System.out.println("TOTAL_ MEMORY = "+totalMemory +"(字节)"+(totalMemory/(double)1024/1024) + "MB");
- }
- }</span>