2021JVM

JVM

一、class加载过程

加载loading:class文件加载到内存,加载到方法区,在堆中生成一个class对象

验证verification:验证是否符合class文件规范,验证是否符合java语言规范

准备preparation:为静态变量分配内存,设置默认值

解析resolution:将常量池内的符号引用转为直接引用(如物理内存地址指针)

初始化initializing:为变量赋真正的值,执行静态语句块,如果发现父类没初始化触发父类初始化

 

二、类加载器

Bootstrap 最顶层的加载器,加载JDK核心类,rt.jarString用的C++实现,获取classloadnull

Extension 加载jre扩展包、ext下的包

Application 加载我们写的类,加载classpath的类

CustomClassLoad 自定义类加载器

 

三、双亲委派模型

先找自定义类加载器是否已经加载,如果没有让上一层查找是否已经加载,找到顶层都没找到,查看顶层是否可以加载,如果可以,加载返回,如果不可以,向下反馈去加载,直到找到可以加载的类加载器,都没找到抛出classNotFind异常,

使用双亲委派模型主要是考虑安全问题,都能加载java内部的类,如String就会不安全

 

 

类加载器:可以实现热部署、动态代理

 

四、缓存行

读入CPU缓存时,不是读什么放什么,而是把之后的64位都放入缓存,称缓存行。

可以让两个变量处于不同缓存行,防止互相更新缓存导致效率变低

 

五、对象的创建过程

首先检查这个类是否已被加载,没有执行相应的类加载过程,加载后为对象分配内存,如果堆是规整的,则将指针向空闲部分移动对象的大小,分配移动的空间(指针碰撞),如果堆不是规整的,则需要有一个空闲列表,记录哪些内存是可用的(空闲列表),serialParNew垃圾收集器是使用的指针碰撞,CMS使用的空闲列表;分配时多线程需要同步处理,也可以将堆根据不同线程分成不同块,分配时先在线程对应块中分配,分配不下再使用同步(TLAB),可通过-XX+UserTLAB参数设定;赋初始值;然后将对象头信息填充;赋默认值;执行init方法

 

六、对象头的信息

对象hash码、对象分代年龄、锁信息、是否偏向锁

 

七、对象的内存占用情况

对象头 8字节

classPointer类指针,指向class类,默认压缩4个字节,不压缩8个字节

实例数据

padding对齐,需要对齐为8的倍数

八、对象访问定位

T t = new T

两种方式:

  1. 句柄池,t指向句柄,句柄指向TClass对象,对象移动可以只移动句柄指针
  2. 直接指针,直接指向TT指向class对象,访问速度快

 

九、java运行时数据区域

 

PC程序计数器:存放指令位置

heap堆:

JVM stacks虚拟机栈:一个方法一个栈帧,栈帧里有:局部变量表、操作数栈、动态链接(A方法调B方法,存B方法的位置)、返回地址(A调用了BB的返回值地址)

native stacks 本地方法栈:

method area 方法区:

1.8之前是perm Space 永久区,字符串常量在此区,固定内存

1.8之后是meta space 元数据空间,字符串常量在堆,可无上限内存

 

十、怎样找到垃圾去回收

引用计数法:循环引用不会被收集

可达性算法:是否与GC root相连,静态变量、常量池、class对象

 

十、清除算法

标记清除:适合存活对象比较多的地方,会产生碎片

复制算法:适合存活对象比较少的情况,会造成空间浪费

编辑整理:将存活的对象移动到一起,需要移动对象,效率低,不会产生碎片、不会空间浪费

 

十一、分代

新生代:eden(伊甸区),survivor(幸存区),survivor(幸存区) 811

老年代:

大对象直接分配到老年代,防止新生代复制大对象

垃圾回收一次后存活的放入survivor,多次回收后还存活放入老年区(默认15次)

动态年龄:survivor区中有某个年龄占用的空间大于一半,则大于该年龄的对象进入老年代

 

十二、垃圾收集器

单线程:serial年轻代、serial old 老年代(十几M-XX+UserSerialGC

  只有一个线程GC,停顿时间长

多线程:Parallel年轻代、Parallel Old 老年代(几百M-XX+UserParallelGc

多个GC线程,但是GC 时也需要工作线程停顿

CMS真正的多线程:可以不停止其他工作线程,过程:

初始标记:找到根对象(单线程,标记对象较少)

并发标记:把其他连接根对象的标记(多线程)

重新标记:把并发标记中发生变动的重新标记(单线程)

并发清理:清理没有标记的

并发清理时可能产生新的垃圾(浮动垃圾),等下一次GC清理

CMS问题:使用标记清除,内存碎片,碎片太多会使用serial old清理,也会造成卡顿

可以降低CMS阈值 -XXCMSInitiatingOccpancyFraction,勤CMS,默认68%

 

G1:将整个堆划分为多个大小相等的独立区域(Region),新生代和老年代不是物理隔离,都是一部分region集合;G1会跟踪各个Region里垃圾堆积的价值大小(回收所获得的空间大小以及回收时间的经验值),维护一个优先列表,优先回收价值最大的区域(garbage

-First,每个region里都维护一个Rsetrememberset),记录着其他区域的对象到本区域的引用。

 

十三、三色标记

黑色:自身和成员变量都已标记

灰色:自身已被标记,成员变量未被标记

白色:未被标记的对象

 

并发标记时可能会漏标,黑色多了成员变量,白色失去灰色的引用,可以将黑色标记为灰色

SATB把消失的引用推到GC的堆栈,扫描一遍标记,与rememberset配合不需要扫描整个堆

十四、GC调优

  1. JVM规划和预调优

选定最适合的垃圾回收器

计算内存需求

选定CPU

  1. 运行JVM运行环境

加大内存还是卡顿,内存越大,FGC时间越长,改用CMSG1

  1. 解决JVM运行时出现的问题

CPU高怎么调优

有线程在占用系统资源

1.导出哪个进程CPU高(top

2.该进程中的哪个线程CPU高(top -Hp #{pid}

3.导出进程中所有线程的堆栈(jstack #{pid}) 关注WAITING的,waiting on <0X00000000088ca3310>...等待哪个锁

找出哪个线程持有这把锁<0X00000000088ca3310>

4.查找哪个方法(jstack

内存高怎么调优

1.导出堆内存(jmap

2.分析(jhatjvisualvmmatjprofilejconsole

 

生产一般不用图形化页面,会影响服务的效率,测试,压测的时候使用

 

 

使用jmap -histo #{pid}|head -20 (前20个)命令,查看哪个类比较多

 

生产配置 -XX+HeapDumpOnOutOfMemoryError OOM时会自动产生堆转储文件,jmap -dump  #{pid} 也会影响生产服务器,可以服务器隔离

jvisualvm可以导入dump文件

多个服务器高可用

在线定位:arthas

posted @ 2021-09-11 20:33  乔儿的终极小迷弟  阅读(83)  评论(0编辑  收藏  举报