深入理解Java虚拟机整理
JVM虚拟机
内存模型
程序计数器
- 存储执行字节码的地址
栈
-
JVM栈
-
本地方法栈
-
-Xss2m
- 栈内存
-
堆
-
回收机制
-
新生代
-
Eden
- 无多余空间时出发Minor GC
-
Survivor
-
-Xmn10M
- 新生代内存10M
-
-XX:SurvivorRatio=8
- Eden和Survivor的空间比例是8:1
-
minor gc
-
-
老年代
- major gc
- full gc
-
-
堆内
-
-Xms10m
- 初始化堆内存
-
-Xmx20m
- 最大堆内存
-
-XX:+HeapDumpOnOutOfMemoryError
- 保存堆内存信息
-
-
堆外(直接内存)
-
不受JVM限制
-
-XX:MaxDirectMemorySize=10m
- 最大直接内存
-
方法区
-
存储类信息、常量、静态变量
-
-XX:PermSize=10m
- 方法区内存
-
-XX:MaxPermSize=20m
- 最大方法区内存
-
-verbose:gc
- 输出gc日志
-
-verbose:class
-
-XX:+TraceClassLoading
-
-XX:+TraceClassUnLoading
垃圾收集(Grabage Collection)
存活判定算法
-
引用计数法
- 相互引用无法回收
-
可达性分析法
- GC Roots
-
引用
-
强引用
- 明确赋值引用
-
软引用
- 在无足够内存时回收
-
若引用
- 下一次gc时回收
-
虚引用(幽灵/幻影)
- 回收时收到系统通知(finalize)
-
收集算法
-
标记-清除
- 标记垃圾并清除
- 效率不高
- 容易产生空间碎片
-
复制
- 把存活对象复制到另一块相同大小的区域,回收原区域后再把数据复制回原区域
- 代价太高,内存利用率只有一半,一般可以分配8:1:1比例
- 适合新生代回收
-
标记-整理
- 移动存活对象到一端,然后直接清理末尾端意外端内存
- 适合老年代回收
-
分代收集
-
根据对象生存周期分为多个代,各个代应用不同的算法
-
新生代
- 复制算法
-
老年代
- 标记整理算法
-
垃圾收集启动时间
- 到达safepoint
- 线程在安全区域
垃圾收集器
-
Serial
-
新生代单线程收集
-
复制算法
-
client模式下默认的新生代收集器
- 新生代内存一般配置的不大
-
可以和CMS配合工作
-
-
ParNew
- 新生代多线程收集
- 复制算法
- server模式下首选的新生代收集器
- 可以和CMS配合工作
- -XX:UseParNewGC
-
Parallel Scavenge
-
新生代多线程收集
-
复制算法
-
可控的吞吐量(吞吐量优先)
- 吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
- 适合交互类程序
- 频繁收集(停顿时间过小)会造成吞吐量下降
-
-XX:MaxGCPauseMillis
- 最大垃圾收集停顿时间(单位毫秒)
-
-XX:GCTimeRatio
- 吞吐量大小
-
-XX:UseAdaptiveSizePolicy
- 动态调整该收集器的参数
-
-
Serial Old(MSC)
- 老年代单线程收集
- 标记-整理算法
- client模式下收集器
-
Parallel Old
- stop the world
- 老年代多线程收集
- 标记-整理算法
- 适合吞吐量优先的场景
-
CMS
-
标记-清除算法
-
过程步骤
-
初始标记
- stop the world
- 标记GC Roots能直接关联的对象
-
并发标记
- GC Roots Tracing
-
重新标记
- stop the world
-
并发清除
-
-
比较
-
优点
- 并发收集
- 低停顿
-
缺点
-
cpu资源敏感
-
本次无法处理浮动垃圾
- 并发清理阶段产生的垃圾本次无法回收
-
无法解决内存碎片
-
-
-
-
G1
- 停顿时间更可控
工具
jps(虚拟机进程状态)
jstat(虚拟机统计信息监控)
jinfo(配置信息)
jmap(内存映像)
jhat(虚拟机堆转储快照分析)
jstack(Java堆栈跟踪)
JConsole
JVisualVM
类加载机制
类加载步骤
-
加载
-
数据来源
- zip包读取
- 网络读取
- 计算生成
- 文件生成
- 数据库读取
- .......
-
-
验证
-
文件格式验证
- 魔数(0xCAFEBABE)
- 主、次版本号
- 常量类型是否支持
- 常量索引是否不存在
- 常量是否符合utf编码
- Class文件各部分是否有被删除或者附加其他的信息
- .........
-
元数据验证
-
字节码验证
-
符号引用验证
-
-
准备
-
解析
- 类和接口解析
- 字段解析
- 类方法解析
- 接口方法解析
-
初始化
-
使用
-
卸载
类加载器
-
启动类加载器(Bootstrap ClassLoader)
-
其他类加载器
-
扩展类加载器(Extension ClassLoader)
-
应用程序类加载器(Application ClassLoader)
- 自定义类加载器1(User ClassLoader)
- 自定义类加载器2(User ClassLoader)
- 自定义类加载器3(User ClassLoader)
- 自定义类加载器......(User ClassLoader)
-
-
双亲委派模型
- 一个类加载器收到类加载的请求,他首先不会自己去尝试加载这个类,他会把这个请求委派给父类加载器去完成,当父类反馈无法加载时,子类才会去尝试加载
- 启动类加载器 <- 扩展类加载器 <- 应用程序类加载器 <- 自定义类加载器