第三章JVM

3.1 JVM 基础 3.2 JVM 内存布局及三色标记算法 3.3 JVM 调优

3.1 JVM 基础

基础主要简单过一下,不了解的百度搜很多
Java理解

平台无关性-- javac编译 javap反汇编,一次编译到处运行
GC垃圾回收
语言特性--泛型,反射等
面向对象--封装,继承,多态
类库--Java本身集合,IO等
异常处理

异常处理
Throwable -> error 和 exception
exception -> runtimeException 和 非runtimeException
error 是JVM负责
runtimeException 是程序负责
checkedException 也就是非runtime是 Java编译器负责

类加载过程

作者:柯西王子
链接:https://www.nowcoder.com/discuss/401895?type=2
来源:牛客网
类加载器的本质其实就是通过文件操作扫描到应用classpath下的Jar包,然后读取
Jar包里的class文件,经过解析,校验等等一堆乱七八糟的操作之后,再将文件里
的字节码内容加载到内存里,供后面类实例化为对象使用,实例化对象的时候会根
据已加载的类信息去做分配内存,初始化成员变量等等一些工作

JVM架构(稍微看看即可)
ClassLoader 根据特定格式,加载class文件到内存
Runtime Data Area 是JVM内存空间模型
Execution Engine 解析命令到操作系统
Native Interface 不同语言的原生库为Java使用

反射
简单略

双亲委派机制

BootStrapClassLoader C++编写加载核心库
ExtClassLoader: Java编写,加载扩展库
AppClassLoader:Java编写,加载程序所在目录
自定义ClassLoader:Java编写,定制化加载

定义流程--略
Why use--避免重复加载
How 自定义? extend ClassLoader 
-> 重写findClass 不打破双亲
-> 重写loadClass 打破双亲

Java内存模型

线程私有的--程序计数器,虚拟机栈,本地方法栈
线程共有的--MetaSpace,堆(常量池和堆)

各自定义,元空间方法区,Intern JDK6改动等等太基础略

GC

引用计数法
可作为GC root对象:虚拟机栈,方法区,活跃线程,本地方法栈中各种对象等
标记清除算法
标记整理算法
复制算法
年轻代
老年代
触发full GC条件
常用垃圾收集器
stop-the-world
safepoint
强引用,软引用,弱引用,虚引用,引用队列
CMS 初始标记,并发标记,重新标记,并发清除及原理(性能不咋地,一直被嫌弃)
G1 堆内存划分,维护优先级,会清除垃圾最多的
太基础略

JMM内存模型
happen-before原则等等,蛮重要的略

3.2 JVM 内存布局及三色标记算法

对象在内存中布局

普通对象

对象头(8字节)
类型指针(4字节)
实例数据(根据具体数据判断,一个int4字节,一个long8字节推类)
对齐 (当整个字节不能被8整除时,则填冲到被8整除)

数组对象

对象头(8字节)
类型指针(4字节)
数组长度
对齐 (当整个字节不能被8整除时,则填冲到被8整除)

一般Java 类型指针64位,但是JVM默认开启compressedPointer会压缩到4字节。compressedOops也会压缩普通对象字节,如String默认是8字节,但是String会被压缩到4字节

例题
User{
int id;
String name;

整个类占多少字节?

对象头8字节,类型指针4字节,int4字节,string4字节,对齐4字节(因为前面只有20字节不能被8整除,自动填充4字节)。总共24字节

垃圾回收算法
CMS 三色标记算法-标错+写屏障
G1 三色标记算-STAB+写屏障
ZGC 颜色指针,着色指针+读屏障

三色标记算法
对象分三种类型:黑色,灰色,白色

黑色指确认不是垃圾并且成员变量已找完
灰色指确认不是垃圾,但是还没有识别成员变量
白色指还没有确认自己是不是垃圾,会被当成垃圾回收

遍历所有灰色对象,把灰色对象下白色成员变量都变成灰色后自己变成黑色。
依次反复知道遍历完整个灰色对象。然后垃圾回收所有白色对象,因为这写白色
对象不可达

情况分析

黑色对象A—(引用)—> 灰色对象B --(引用)—> 白色对象C

场景1

灰色对象和白色对象中间引用消失
这种情况不会产生问题,白色对象本身就是浮动垃圾,
不可达,就应该被清除

场景2

灰色对象和白色对象中间引用消失,但是黑色对象和白色对象中间增加引用
这种情况会产生问题,黑色对象因为已经标记查完成员变量,所以不会再查
这个白色对象,白色对象将会被当成垃圾回收。但是白色对象C现在已经和
黑色对象A产生引用,可达了,不应该是垃圾,产生了矛盾

对于场景2的问题

CMS解决方案:写入屏障方法,A,C新增引用时候,通过写屏障算法把C白色对象
强行变成灰色,这样下一次就可以继续遍历灰色对象C了,C不会被垃圾回收

那么CMS为什么需要重新标记呢?

并发标记阶段加入的新白色对象不能直接GC回收,所以需要重新标记上述步骤

最后就是并发清除—标记清除算法,会产生严重碎片化

CMS 垃圾回收器可以和用户线程一起并发执行,如果这时候用户线程内存空间不够怎么办?

这个时候会报错,可以用Serial Old 垃圾回收器
替代 CMS 进行 stop the world 垃圾回收

3.3 JVM 调优

调优步骤

1 熟悉业务场景:启动慢,响应慢,吞吐量低等等
2 目标:内存占用,低延迟,吞吐量大
3 收集日志:通过参数收据GC日志,通过JDK工具实时查看GC状态
4 分析日志:可以通过Arthas辅助分析日志
5 调整参数:切换垃圾收集器,调参数等等

场景1 (定位处理OOM)

1 jps 查找进程id号(如id号1011)
2 jmap -histo 1011 | head 20 查看哪些类产生多少个对象
(少用jmap,因为jmap时候会影响线上性能)
3 发现线程池实例不停增加,问题找到
4 可以用redefine线上内存中直接修改代码,不停服务器,问题解决

场景2(性能调优)

1 java -Xmax 1024 m -X loggc: xxxx -jar xxxxx
比如测试环境下,配置参数启动项目并打印日志
2 jstat -gc id xxxx
查看gc次数和gc时间(PerallelGCThreads默认2个线程)
3 配置PerallelGCThreads4个线程重新运行,再jstat比较发现gc时间变大了,
这方法不行
4 改CMS再重新运行,再jstat比较发现gc时间依然变大不可取
5 改G1,发现仍然不咋地
6 。。。。。不停改看哪个性能好用哪个
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章