【实战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 直接内存
方法区是放在元空间中,属于操作系统中的直接内存。