【实战JVM】-基础篇-03-Java内存结构
- 1 运行时数据区
- 1.1 总览
- 1.2 程序计数器
- 1.2.1 是否会内存溢出
- 1.3 java虚拟机栈
- 1.3.1 栈帧的组成
- 1.3.1.1 局部变量表
- 1.3.1.2 操作数栈
- 1.3.1.3 帧数据
- 1.3.1.3.1 动态链接
- 1.3.1.3.2 方法出口
- 1.3.1.3.3 异常表
- 1.3.2 是否会内存溢出
- 1.3.3 设置虚拟机栈大小
- 1.3.3.1 注意事项
- 1.4 本地方法栈
- 1.5 堆
- 1.5.1 是否会内存溢出
- 1.5.2 Java堆
- 1.5.2.1 Arthas查看堆内存
- 1.5.2.2 默认参数
- 1.6 方法区
- 1.6.1 元信息
- 1.6.2 运行时常量池
- 1.6.3 字符串常量池
- 1.6.4 神奇的intern
- 1.6.5 方法区实现
- 1.6.6 是否会内存溢出
- 1.6.7 静态变量的存储
- 1.7 直接内存
1 运行时数据区
运行时数据区负责管理jvm使用到的内存,比如创建对象和销毁对象。
1.1 总览


1.2 程序计数器


1.2.1 是否会内存溢出

简单来说,PC计数器就两个作用:
- 对于单线程环境,保存下一条需要执行的指令的内存地址。
- 对于进程来说,用于保存上下文信息,方便切换。
1.3 java虚拟机栈

1.3.1 栈帧的组成

1.3.1.1 局部变量表


- 起始PC:表示根据字节码哪一行可以使用该局部变量
- i就是在0、1之后完成初始化,234可以使用,所以长度是3,j就是1


静态方法的局部变量表不包括自己this,而实例方法中的局部变量表存放着this,局部变量也会占用槽



1.3.1.2 操作数栈

1.3.1.3 帧数据
1.3.1.3.1 动态链接

1.3.1.3.2 方法出口

1.3.1.3.3 异常表

1.3.2 是否会内存溢出


1.3.3 设置虚拟机栈大小

1.3.3.1 注意事项

1.4 本地方法栈

1.5 堆

成员变量存放于堆中,局部变量存放于栈中(由局部变量表维护)。
jdk8之前,静态变量存放在方法区中,jdk8之后,静态变量存放在堆中。
堆是线程共享的,所以针对需要多线程使用的环境,可以将变量变为静态变量以达到我们的需求。
1.5.1 是否会内存溢出

1.5.2 Java堆

1.5.2.1 Arthas查看堆内存
dashboard -i 刷新频率(毫秒)
查看堆内存used、total、max

1.5.2.2 默认参数
如果不设置默认参数,默认max是系统内存的1/4,total默认是系统内存的1/64。

建议将-Xmx和-Xms设置为相同的值,这样在程序启动之后可使用的总内存就是最大内存,而无需向java虚拟机再次申请,减少了申请并分配内存时间上的开销们也不会出现内存过剩之后,堆收缩的情况。

1.6 方法区

1.6.1 元信息

1.6.2 运行时常量池
解析阶段将常量池中的符号引用替换为直接引用

1.6.3 字符串常量池




1.6.4 神奇的intern

jdk6

jdk7之后

主要是因为jdk7之后,字符串常量池是在堆中的,而方法区是在永久代里的;jdk8字符串常量池是在堆中的,而方法区是在元空间里的。
1.6.5 方法区实现


1.6.6 是否会内存溢出

没有过高要求设置256M即可,但是元空间一定要设置。
1.6.7 静态变量的存储

1.7 直接内存
方法区是放在元空间中,属于操作系统中的直接内存。






![[JDK工具-5] jinfo jvm配置信息工具](https://img-blog.csdnimg.cn/direct/c821a67cd234429a805ba3976bb529e5.png)














