JVM介绍和垃圾回收

531 阅读5分钟

知识点:
1)什么是JVM
2)运行时数据区
3)内存模型
4)垃圾收集器

建议书籍:
《深入理解java虚拟机》
这本书建议是具备一定java能力的同学进阶必看的书籍。

什么是jvm

功能:
1)软层面做了一个翻译
2)内存管理

为什么要学习JVM?
当我们出现内存泄漏和内存溢出的时候,由于内存都是被JVM管理,所以我们必须要去了解这块内容。

运行时数据区

java代码无非就是数据,指令,控制。
1)程序计数器:指向当前线程正在执行的字节码指令的地址 行号
2)虚拟机栈 存储当前线程运行方法所需要的数据,指令,返回地址
局部变量表 操作数栈 动态链接 出口等等
3)本地方法栈 本地方法native
4) 方法区: 类信息 常量(1.7) 静态变量 JIT
5)堆 : 存放对象实例

1.8以前的版本

1.8之后

永久代存在在方法区

meta space 在直接内存中

  1. 规避永久代溢出的问题
    2)有点类似于arraylist 可以自动扩容

新生代回收算法:复制回收算法
采取8:1:1的话那么只浪费10%
对象的生命周期不一样--》分代
98%在minor gc的时候会被回收掉 【minor gc 清理的是eden区】
s1放不下 分配担保 由我们老年代来担保

理想情况下应该避免对象进入老年代
【major gc 清理的是老年代,我们要尽量避免使用majorgc,因为这个比minor gc 慢十倍】

默认的JVM参数:
新生代:老年代 1:2

什么样的对象应该被gc
1)引用计数法
2)可达性分析法
可以作为GC root对象:
虚拟机栈中本地变量表引用的对象
方法区
- 类静态变量引用的对象
- 常量引用的对象
本地方法栈中JNI引用的对象

不可达是不是就一定会被回收
finalize() 挽救一次

举例: Object obj=new Object();

obj首先现在新生代的eden区申请一个空间

官网查看各种配置参数
www.oracle.com/technetwork… 注意看这句

代表有些配置是非官方的,不一定适用于所有的JVM
所以需要查下面的表格

参数解释
-Xms20M starting 堆的起始大小
-Xmx max 堆的最大大小
-Xmn new 堆的新生代大小

新生代比例参数设置 默认是8:1:1
-XX:SurvivorRatio=8

指针碰撞和栈上分配
栈上分配 -XX:+/-UserTLAB (Thread Local Allocation Buffer)

Free List 空闲列表

先掌握一些常用的概念和配置
对象很大
-XX:PretenureSizeThreshold=3145728 【3M】
ps:
当创建的对象超过指定大小时,直接把对象分配在老年代中。
-XX:PretenureSizeThreshold=3145728 参数设定超过对象超过多少时,分配到老年代中,此例为3M(310241024)。

长期存活的对象【多次minor gc】 每次gc存活都有一个年龄+1 默认是15
-XX:MaxTenuringThreshold=1
ps:
这边设置一个撑过多少minor gc的对象能够放入老年代

动态对象年龄判断
相同年龄所有对象的大小总和> survivor空间大小的一半 这些对象直接晋级到老年代

分配担保
minor GC 判断老年代是否有空间
老年代最大可用连续空间是否 > 新生代所有对象总空间

划分GC的原因是因为不同的gc分代效率的问题
minor GC
major GC
full GC

什么时候可能触发Full GC呢
1)Perm空间不足;
2)CMS GC出现了promotion failed和concurrent mode failure 。
concurrent mode failure发生的原因一般是CMS正在进行,但是由于老年代空间不足,需要尽快回收老年代里面的不再被使用的对象,这时停止所有的线程,同时终止CMS,直接进行Serial Old GC
3)统计得到的Young GC晋升到老年代的平均大小大于老年代的剩余空间
4)主动触发Full GC(执行jmap -histo:live [pid])来避免碎片问题

引用:
强引用 Object obj=new Object() gcroot 可达

软引用 SoftReference

弱引用

虚引用

判断对象是否需要被回收
1)引用计数法 【无法解决对象互相引用的问题】
2)可达性分析法

垃圾回收算法:
1)标记清除
2)复制回收
3)标记整理
4)分代收集

垃圾收集器

上三个 复制回收算法
1)Serial 单线程 Stop The World
2)ParNew 多线程
-XX:ParallelGCThreads
3)Parallel Scavenge
吞吐量=运行用户代码时间/(运行用户代码时间+垃圾回收时间)
-XX:MaxGCPauseMillis=n
-XX:GCTimeRatio=n
-XX:UseAdaptiveSizePolicy
4)CMS
标记-清除算法
减少回收停顿时间
初始标记-并发标记-重新标记-并发清除
-XX:+ UseCMSCompactAtFullCollection Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长
-XX:+CMSFullGCsBeforeCompaction 设置进行几次Full GC后,进行一次碎片整理
-XX:ParallelCMSThreads 设定CMS的线程数量(一般情况约等于可用CPU数量)
5)Serial Old
CMS的备用预案 Full GC 老年代已经塞满了 分配担保没有空间
标记整理算法
6)Parallel Old
标记整理算法
7)G1
相比于cms 能够处理浮动垃圾

回收的时间节点

如何查看当前的垃圾回收器
-XX:+PrintFlagsFinal
-XX:+PrintCommandLineFlags
server client
MBean

GC日志
1.输出日志
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-Xloggc:/home/administrator/james/gc.log
-XX:+PrintHeapAtGC
2.日志文件控制
-XX:-UseGCLogFileRotation
-XX:GCLogFileSize=8K
3.怎么看

JDK自带的 监控工具
docs.oracle.com/javase/8/do…
jmap -heap pid 堆使用情况
jstat -gcutil pid 1000
jstack 线程dump
jvisualvm
jconsole

MAT
help.eclipse.org/oxygen/inde…
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/home/administrator/james/error.hprof

怀疑:
1.看GC日志 126719K->126719K(126720K)
2.dump
3.MAT
1.占用Retained Heap
2.看有没有GC Root指向

VM参数
www.oracle.com/technetwork…