Bootstrap

JVM内存模型详细解析

JVM内存模型详情解析

一、结构图

在这里插入图片描述

NOTE: string常量池 存在 堆内存中

二、各部分详情解析
1、堆
1)老年代

对象年龄(经过一次 monitor GC 年龄加1) >15 的会存到 老年代

2)年轻代
  • eden
    • 内存分配默认是 年轻代 80%
  • survivor
    • 内存分配默认是 年轻代20%(from 和 to 区分别占10%)
3)常量池:

​ String常量 存储在堆中

2、虚拟机栈
1)局部变量表
  • 存储的数据:存放方法参数和方法内定义的局部变量
  • note:局部变量表的容量以变量槽(Variable Slot)为最小单位,Java程序编译为Class文件时,就在方法的Code属性中的max_locals数据项中确定了该方法所需分配的局部变量表的最大容量。(最大Slot数量)
2)操作数栈
  • 存储的数据
    • 和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。但是和前者不同的是,它不是通过索引来访问,而是通过标准的栈操作—压栈和出栈—来访问的
  • note:操作数栈的最大深度也在编译的时候写入到方法的Code属性max_stacks数据项中,操作数栈的深度都不会超过max_stacks中设置的最大值。
3)动态链接
  • **介绍:**Java 是在运行期间动态链接的,所以为了支持动态链接,需要将方法区里面的符号引用转为直接引用(即:给出地址),这就叫动态链接
4)方法出口信息

note:栈中每一个线程 都会创建自己的 栈帧,每个栈帧中又会分为以上四种信息

源码及字节码解析栈
3、本地方法栈

和虚拟栈类似,只是存储native修饰的 方法信息

4、元数据区/元空间
1)类信息
2)静态变量
  • static修饰的变量
3)常量池
  • 常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种申明方式;当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。

  • Java是一种动态链接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组的常量值外,还包含一些以文本形式出现的符号引用,比如:

    ​ 类和接口的全限定名;

    ​ 字段的名称和描述符;

    ​ 方法的名称和描述符。

    在C语言中,如果一个程序要调用其它库中的函数,在链接时,该函数在库中的位置(即相对于库文件开头的偏移量)会被写在程序中,在运行时,直接去这个地址调用函数;

    而在Java语言中不是这样,一切都是动态的。编译时,如果发现对其它类方法的调用或者对其它类字段的引用的语句,记录进class文件中的只能是一个文本形式的符号引用,在连接过程中,虚拟机根据这个文本信息去查找对应的方法或字段。

    所以,与Java语言中的所谓“常量”不同,class文件中的“常量”内容很丰富,这些常量集中在class中的一个区域存放,一个紧接着一个,这里就称为“常量池”。

  • class文件共有11种常量表

常量表类型标志值(占1 byte)描述
CONSTANT_Utf81UTF-8编码的Unicode字符串
CONSTANT_Integer3int类型的字面值
CONSTANT_Float4float类型的字面值
CONSTANT_Long5long类型的字面值
CONSTANT_Double6double类型的字面值
CONSTANT_Class7对一个类或接口的符号引用
CONSTANT_String8String类型字面值的引用
CONSTANT_Fieldref9对一个字段的符号引用
CONSTANT_Methodref10对一个类中方法的符号引用
CONSTANT_InterfaceMethodref11对一个接口中方法的符号引用
CONSTANT_NameAndType12对一个字段或方法的部分符号引用

(1) CONSTANT_Utf8 用UTF-8编码方式来表示程序中所有的重要常量字符串。这些字符串包括: ①类或接口的全限定名, ②超类的全限定名,③父接口的全限定名, ④类字段名和所属类型名,⑤类方法名和返回类型名、以及参数名和所属类型名。⑥字符串字面值

表格式: tag(标志1:占1byte) length(字符串所占字节的长度,占2byte) bytes(字符串字节序列)

(2) CONSTANT_Integer、 CONSTANT_Float、 CONSTANT_Long、 CONSTANT_Double 所有基本数据类型的字面值。比如在程序中出现的1用CONSTANT_Integer表示。3.1415926F用 CONSTANT_Float表示。

表格式: tag bytes(基本数据类型所需使用的字节序列)

(3) CONSTANT_Class 使用符号引用来表示类或接口。我们知道所有类名都以 CONSTANT_Utf8表的形式存储。但是我们并不知道 CONSTANT_Utf8表中哪些字符串是类名,那些是方法名。因此我们必须用一个指向类名字符串的符号引用常量来表明。

表格式: tag name_index(给出表示类或接口名的CONSTANT_Utf8表的索引)

(4) CONSTANT_String 同 CONSTANT_Class,指向包含字符串字面值的 CONSTANT_Utf8表。

表格式: tag string_index(给出表示字符串字面值的CONSTANT_Utf8表的索引)

(5) CONSTANT_Fieldref 、 CONSTANT_Methodref、 CONSTANT_InterfaceMethodref 指向包含该字段或方法所属类名的 CONSTANT_Utf8表,以及指向包含该字段或方法的名字和描述符的 CONSTANT_NameAndType 表

表格式: tag class _index(给出包含所属类名的CONSTANT_Utf8表的索引) name_and_type_index(包含字段名或方法名以及描述符的 CONSTANT_NameAndType表 的索引)

(6) CONSTANT_NameAndType 指向包含字段名或方法名以及描述符的 CONSTANT_Utf8表。

  • 八种基本类型的包装类和对象池

    java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用常量池,也即对象不负责创建和管理大于127的这些类的对象。

5、程序计数器
1)线程执行到的行号,native方法 行号为 null
三、内存溢出
会产生内存溢出的区域
  1. 元数据区(元空间)

note:只有程序计数器不会出现内存溢出

;