JVM总结

JVM总结

java源文件 -> 编译为class文件 -> 加载到jvm(类加载)

在这里插入图片描述

类加载过程

1.装载

  • 通过全路径找到class文件,ClassLoader.find(name)
  • 类加载的双亲委派原则:当一个类加载器要加载一个类时,它会先委托自己的父加载器来加载,只有当父加载器无法加载类时,才会自己去加载。

2.链接

  • 验证:验证类的格式正确性
  • 准备:静态变量初始化为默认值(例如int类型是0)
  • 解析:类中的符号引用转换为直接引用

3.初始化

  • 静态变量赋值
  • 执行静态代码块

JVM的运行时数据区

在这里插入图片描述

1.方法区

  • 类信息
  • 常量、静态变量

JDK1.7:PermSpace 永久代

JDK1.8:MetaSpace 元空间

2.堆

  • 对象存储在堆上

  • 堆可分为年轻代(Eden,S0,S1)和老年代。

3.虚拟机栈

  • 方法执行:栈帧的压入和弹出
  • 栈帧:
    • 局部变量表
    • 操作数栈
    • 动态链接
    • 方法返回地址

4.本地方法栈

  • 与虚拟机栈类似,native方法

5.程序计数器

  • 记录下一条指令的地址

逃逸分析

  • 逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中,称为方法逃逸。

  • 在java 虚拟机中,对象是在java堆中分配内存的,这是一个普遍的常识。但是,有一种特殊情况,那就是如果经过逃逸分析后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需要在堆上分配内存,也无需进行来集回收了。

Java对象内存布局

一个Java对象的内存布局包括:对象头、实例数据、对齐填充

在这里插入图片描述

  • 可以根据这个结构估算出一个java对象的大小

  • 对象头中的MarkWord包含三类信息:

    • 对象的hashCode:当调用了hashCode方法后会写入到此处
    • GC年龄:存储大小4位,故最大值为15,所以GC的年龄阈值MaxTenuringThreshold参数最大值为15
    • 锁标识:synchronized多线程同步时会使用到这部分信息
  • Class Pointer:指向方法区中Class信息的指针

  • 对齐填充是为了提升性能,假设对象是不等长的,那么为了获取一个完整的对象,就必须一个字节一个字节地去读,直到读到结束符,但是如果8字节对齐后,获取对象就可以以8个字节为单位进行读取,快速获取到一个对象,是一种以空间换时间的设计方案。

GC

  • Minor GC 或 Yong GC(年轻代):当Eden区或S区不够用了

  • Major GC(老年代):当老年代不够用了,一般会伴随Minor GC

  • Full GC(年轻代 + 老年代)

  • 方法区GC,GC日志中通常会显示为【Full GC(Metadata GC Threshold)xxxxx】

Metaspace

  • metaspace使用的是本地内存
  • metaspace的初始大小并不等于设置的MetaspaceSize参数。随着类的加载,metaspace会不断进行扩容。
  • metaspace的最大值默认是没有上限的,除非配置MaxMetaspaceSize
  • metaspace发生GC的时机:
    1. metaspace在没有更多的内存空间的时候。
    2. JVM内部有一个叫做_capacity_until_GC的变量,一旦metaspace使用的空间超过这个变量的值,就会对metaspace进行回收。这个变量的初始值为MetaspaceSize,但是会自动的在 MetaspaceSize和MaxMetaspaceSize之间进行调整。

垃圾回收

如何判断哪些对象需要回收

  • 引用计数(存在循环引用问题)
  • 可达性分析(GC Root的选择)

回收算法

  • 标记清除(需要遍历,效率较低;内存碎片)
  • 标记整理(效率较低,解决了内存碎片)
  • 复制算法(在垃圾对象多的情况下,效率较高。内存使用率较低)

垃圾收集器

垃圾收集器是对回收算法的落地

新生代:复制算法

老年代:标记清除/整理

在这里插入图片描述

Serial,Seerial Old:单线程

ParNew,ParallelScavenge(更加关注吞吐量)、ParallelOld:多线程

CMS:用户线程和垃圾回收线程并发执行,较短的停顿时间

G1:并发执行,可以设置pause time

垃圾收集器的选择

GC收集器:停顿时间和吞吐量

  • 停顿时间 = 每次执行垃圾回收造成用户线程停顿的平均时间

  • 吞吐量 = 用户线程执行时间 /(用户线程执行时间 + GC时间)

停顿时间小:CMS、G1【set pause time】

吞吐量优先:Parallel Scanvent、 Parallel Old

串行收集:Serial、Serial Old,内存比较小、嵌入式设备

JVM参数

-XX参数

  • 布尔型:-XX:[+/-]name 启动或者停止
  • 非布尔型:-XX:name=value

其他参数[-XX参数的其他写法]

  • -Xms100M 相当于 -XX:InitialHeapSize=100M
  • -Xmx100M 相当于 -XX:MaxHeapSize=100M

命令

  • jps:查看当前java进程
  • jinfo:查看或者修改jvm参数
  • jstat: 查看class装载或者gc信息
  • jstack:查看线程信息(排查死锁)
  • jmap:查看堆信息或者生成堆的dump文件

查看堆的dump文件的工具

  • jconsole
  • jvisualvm
  • arthas:阿里开源的java诊断工具
  • MAT(Memory Analyzer Tool)打开dump文件,详细的分析报告,可能存在问题的代码

查看GC日志的工具

  • gcviewer

JVM调优 - Why?

  • CPU飙升
  • 内存空间不够用
  • GC次数太多,影响用户线程执行效率
  • 提高吞吐量、较少停顿时间

JVM调优-排查堆的使用情况

分析dump文件,排查哪个对象占用内存空间大

JVM调优-排查垃圾回收情况

  • 使用工具查看GC日志
  • 如何通过选择垃圾收集器优化:调整JVM配置后,解析GC日志。关注指标: 吞吐量、停顿时间、GC次数。

使用G1垃圾回收器的调优例子

配置吞吐量平均停顿时间GC次数备注
UseG1GC92.89%0.0107s21
堆内存增加一倍95.68%0.0182s3吞吐量增大,GC次数较少。但是停顿时间变大,原因:更多的内存意味着可以积累的垃圾更多,一次回收的时间会拉长
设置停顿时间为15ms95.02%0.0089s14停顿时间减少了,但GC次数变大,原因:停顿时间减少说明一次GC的标记对象减少了,所以次数多了
  • G1可以设置启动GC的堆存在占比,默认为45,即内存使用率为45%时启动触发GC
  • 使用G1时,不要设置年轻代大小,如果设置了大小则会破环停顿时间的目标。因为G1会自适应的调整年轻代的大小。
  • 增加G1垃圾回收标记线程数量
  • 等等,可参考官网建议

G1和CMS的区别

CMS:标记清除

G1:

  • 标记整理
  • G1把连续的Java堆划分为多个大小相等的Region,每一个Region都可以作为年轻代的Eden空间、Survivor空间,或者老年代空间。
  • 优先收集垃圾比较多的区域
  • CSet
  • 硬件要求:多核、大内存(至少内存6G内存)
  • 等等
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值