JVM

java 结构图

图片.png
Figure 1. 图片.png
  • java基础语法

  • java工具,java、javac、jar、javap等

  • 各种工具包,例如GUI、JDBC、java and util等各种针对不同环境提供的工具包

  • jvm 虚拟机,执行java字节码文件

java为何可以跨平台

java文件编译成class文件,交由jvm进行解释运行,各个平台都有针对平台开发的jvm,相当于翻译,我们自需要完成业务逻辑,表达想法,至于在各个平台如何执行,则交由jvm这个翻译者来进行解释执行,所以说java是编译和解释共存的语言。jvm屏蔽了不同平台机器指令码和硬件的不同。

jvm 调优思路

JVM 内存模型

图片.png
Figure 2. 图片.png

线程独享: 是指当线程开始执行代码时,创建的内存区域,只能此线程进行访问,主要是这些区域都是存放当前线程执行代码的一些内部数据。包含栈、本地方法栈、程序计数器

方法栈

记录代码执行调用的顺序。采用栈结构 first in last out ,这种结构很适合代码执行,方法调用的先后顺序,外面的方法先执行后结束,里面的方法后执行先结束。每个栈帧即为一个方法的调用。

一个栈帧包含以下几个部分

  • 局部变量表: 存放方法内部的局部变量

  • 操作数栈:局部变量的操作,入栈出栈完成业务逻辑

  • 动态链接:对其他方法的调用

  • 方法出口:当此栈帧执行完成后,下一个执行位置,在调用此方法的时候,会记录上一个栈帧的位置,退出时,沿上一个栈帧记录的位置继续执行

本地方法栈

类似于方法栈,针对的native方法。

程序计数器

用于记录线程执行位置,简单可视为行号,占用内存很少。

线程共享: 每一个线程都能访问到。

存放对象,创建的对象都存放在此区域中,此区域涉及到垃圾回收,当对象不再使用或者内存满了,会触发垃圾回收。

元空间

1.8之前是永久代,而且是堆中内存的一部分,1.8之后独立出来,使用直接内存,和基本实际内存关联,和jvm的内存无关。主要存放类信息以及常量、静态变量。

垃圾回收机制

当堆中的对象不再使用或者内存不够用时,会触发垃圾回收。堆中的内存分配,需根据实际 应用可以做调整,以便得到所谓的虚拟机调优。

图片.png
Figure 3. 图片.png

新生代

每次线程运行产生的对象都会现在eden区域进行存放,当新生代中的内存快满时,会触发minor gc,存活的对象将会放在s0或s1区中的一个空白区域,另一个有对象的区域也会进行minor gc, 并记录其分代年龄,当其年龄达到15时,将会放在老年代中。通过可达性算法来判断对象的有效性。

老年代

gc如何判断垃圾

引用计数法

每个对象都包含一个引用计数器,用于存放对其引用的次数,新增引用加1,引用失效减1,如果引用计数器大于0,表示对象还处于活跃状态,当引用为0时,意味着不再使用,标记可回收。

但是这样存在一个问题, 当两个对象相互引用时,可能出现引用计数器不为0,但实际已经是垃圾对象了。

可达性算法

以 GC root 为根节点,生成一个树状结构的引用。当GC root 不在使用,那么树状结构以下的都可标记为垃圾对象。

选定为根节点的条件

  • 栈帧中本地变量表中对象

  • 方法区,常量池引用的对象

  • 加锁的对象(synchronized)

  • 虚拟机内部需要用到的对象

图片.png 图片.png

jvm调优工具

jdk自带的 jvisualvm

启动后,会显示一个可视化客户端,能检测出所有的jvm进程,选择指定进程就可以监控当前进程jvm的一个运行情况

alibaba 开源的 arthas

一个jar可执行文件,同理,启动后,会显示当前机器上所有的jvm线程,选择指定线程,可实时监控,并可根据不同的命令查找运行中出现的问题,用于定位。

stw机制

当进行垃圾回收时,会暂停所有的线程,也即 stop the world。

为什么要设计stw机制?

如果不引入stw机制,当程序在进行gc时,其他线程依旧执行,那么可以一个对象上一秒不是垃圾,由于线程执行完毕,下一刻就变成垃圾了,这是gc在对整个程序进行分析时,就会变得不准确,gc处理过于复杂,还不如暂停所有进程,等gc处理完毕后在恢复所有线程执行。目的就是保证在gc执行时,对象是否是垃圾的状态不可变,减少不确定性。

jvm调优

jvm调优,主要是减少stw的次数以及时间,避免频繁的进行full gc,造成线程暂停,系统卡顿问题。

思路:

  • 合理分配堆中的内存占用,例如正对频繁创建对象,但是对象用后即垃圾,可增大新生代Eden的内存,减少老年代的内存

  • 提高minor gc的频率,虽然次数增多,但是一次gc的时间很短,对用户影响要更小,相当于 10次 1s 的暂停优于 1次 10s的暂停