JAVA JVM运行时数据区详解

时间:2021-12-13 00:45:48

一、前言

这是JVM系列文章的第三篇,这篇文章将对整个JVM运行时数据区和GC垃圾回收详细的介绍。这部分也算是JVM的核心内容了。

 

二、运行时数据区整体概架构

JAVA JVM运行时数据区详解

以下是自己的一句话总结:

分为线程私有和线程共享的两大类,其中程序计数器、虚拟机栈、本地方法栈是属于线程私有的,堆内存及方法区内存是线程共享的。程序计数器主要是记录字节码指令,CPU上下文切换线程,从一个线程切换到另一个线程,需要知道线程执行到哪一步,所以记录这个指令就是很有必要的,程序计数器无OOM和GC的发生。虚拟机栈里面是一个个栈帧,每一个栈帧对应着每一个方法,栈帧又是由局部变量表、操作数栈、方法返回值地址、动态链接组成。虚拟机栈可能会发生栈溢出异常,即starkoverflow本地方法栈是存放本地方法相关的东西;堆是一块很大的空间,整体分为2大块,新生代和老年代,新生代又分了Eden区、S0区、S1区,垃圾回收主要发生在新生代,每一个区对应不同的垃圾回收算法;方法区保存的是一些常量、类的基本信息等,方法区对应的实现在JDK7中是永久代,在JDK8中是元空间。

 

三、程序计数器

用来储存指向下一条指令的地址,是线程私有的,生命周期和线程的生命周期一致。

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

 

四、虚拟机栈

虚拟机栈是线程私有的,内部保存一个个栈帧,每一个栈帧对应一个Java方法的调用,生命周期和线程的生命周期保持一致。先来看看栈的特点。

JAVA JVM运行时数据区详解

1、栈的特点

栈是运行时的单位,而堆是存储的单位。栈的特点是先进后出,后进先出。

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

可以通过参数-Xss来设置栈空间大小

2、栈帧的内部结构

JAVA JVM运行时数据区详解

3、局部变量表

是一个数字数组,主要用于存储方法参数和定义在方法内的局部变量,这些数据类型包括各类基本数据类型,对象引用等,所需的容量大小是在编译期确定下来的,在方法运行期间是不会改变局部变量表大小的。

关于Slot的理解:

JAVA JVM运行时数据区详解

静态变量和局部变量的区别:

JAVA JVM运行时数据区详解

总结:

在栈帧中,与性能关系最为密切的就是局部变量表,在方法执行时,虚拟机使用局部变量表完成完成方法的传递,局部变量表中的数据也是可达性分析中的GC Root,如果一个对象在局部变量表中还有引用,那么根绝可达性分析算法,这个变量就不属于垃圾对象,是不会被GC回收的。

4、操作数栈

操作数栈是栈中栈,也可称为表达式栈,在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈和出栈。主要用于保存计算过程的中间结果。操作数栈,可以看成是临时寄存器,计算过程中变量的临时保存

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

5、动态链接

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

方法重写的本质

JAVA JVM运行时数据区详解

6、方法返回地址

存放调用该方法的PC寄存器的值

JAVA JVM运行时数据区详解

 

五、本地方法栈

管理本地native本地方法,是线程私有的,所谓的本地方法,其实就是一些非Java语言写的代码,这部分代码甚至可以和操作系统CPU进行打交道。

 

六、堆

堆是内存管理的核心区域,是线程共享的,属于JVM级别,也就是一个JVM实例就会有一个堆空间,注意的是虽然堆整体上是线程共享的,但是在内部有一小块空间是线程私有的缓存区TLAB。

几乎所有的对象实例都是在堆中,堆是GC垃圾回收的重点区域。堆整体可以分为新生代和老年代,新生代又分为Eden区和S0和S1区。

JAVA JVM运行时数据区详解

新生代和老年代的比例是1:2,Eden区和s0,s1区所占空间比例是8:1:1

1、设置堆大小的参数

-Xms:用于表示堆区的起始内存,默认情况下,占物理内存大小的64分之一。

-Xmx用于表示堆区的最大内存,默认情况下,占物理内存的四分之一。

通常起始内存和最大内存两个参数设置成一样,目的是为了GC清理完堆区内存后不需要重新分隔
计算堆区的大小,从而提高性能。
查看设置的参数:
方式一:jps(查看进程)  
          jstat -gc 进程id
方式二:-xx:+printGCDetails

2、对象分配过程

JAVA JVM运行时数据区详解

这里s0和s1谁是空的谁就是to,年龄计数器阈值是15,YGC是在Eden区满的时候会触发,s0和s1满的时候不会触发YGC,YGC会将s区以及伊甸园区一起GC

关于垃圾回收,频繁在新生区收集,很少在养老区收集,几乎不在永久区/元空间收集。

JAVA JVM运行时数据区详解

Visualvm是JVM常用调优工具,在JDK的bin下就可以打开

3、堆中的GC

JAVA JVM运行时数据区详解

年轻代(Minor GC)触发机制

JAVA JVM运行时数据区详解

老年代GC(Major GC/Full GC)触发机制

Full GC 触发机制

JAVA JVM运行时数据区详解

4、内存分配策略

JAVA JVM运行时数据区详解

5、什么是TLAB

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

TLAB表明堆不一定是共享的。

6、堆是分配对象存储的唯一选择吗?

如果经过逃逸分析,一个对象并没有逃逸出方法的话,那么就有可能被优化成栈上分配。

逃逸分析手段:

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

注意:JDK6U23版本后,HotSpot默认已经开启逃逸分析。所以我们得出一个结论,开发中能使用局部变量的,就不要使用在方法外定义。JDK7后字符串常量池和静态变量存储在堆中

 

七、方法区

方法区可以看做是一块独立于堆的内存空间,是线程共享的,主要存储类信息、运行时常量池等,也会发生OOM,JDK8前成为永久代,JDK8成为元空间。(元空间和永久代最大的区别是,元空间不再使用JVM内存,而是使用了本地内存技术)

1、方法区概述

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

2、设置方法区内存大小

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

3、如何解决OOM问题?

JAVA JVM运行时数据区详解

4、方法区存储什么

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

5、方法区的演进细节

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

6、方法区的GC

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

JAVA JVM运行时数据区详解

 

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注服务器之家的更多内容!

原文链接:https://blog.csdn.net/qq_43270074/article/details/120038391