1 概述
具有内存动态分配和自动回收的特点
2 运行时内存
![](https://img.haomeiwen.com/i460263/5b767b49e03f449e.png)
2.1 程序计数器(Program Counter Register)
特点
- 线程私有,因为多线程并发回来后要恢复到当前线程之前执行的位置,所以每个线程都会独立拥有一个 PC
- 占用空间极小
字节码行号指示器,解释器通过它来选取下一条执行的字节码指令
- 执行 Java 方法:具体的内容就是指向下一个指令的偏移
- 执行 Native 方法:计数值为空(undefined)
不会有 OutOfMemoryError
2.2 Java 虚拟机栈(Java Stack)
![](https://img.haomeiwen.com/i460263/82114a98da93e49b.jpg)
特点
- 线程私有
- 以栈帧为单位,进行压栈和出栈
结构
整个栈以栈帧为单位
-
局部变量表(Current Variable Table)
以变量槽(Slot)为单位,也成为
有 this 引用,方法参数,定义的局部变量
字节码指令使用从 0 开始索引来使用其中的数据,而 0 Slot 都默认为当前方法所属的实例的引用,即 this
分配多大的局部变量空间在编译期间已经确定
int,float,reference,returnAddress 占一个 Slot ;byte,short,char 会被转成 int;long,double 占两个连续 Slot -
操作数栈(Operand Stack)
以变量槽(Slot)为单位
字节码指令从操作数栈弹出数据,执行计算,再把结果入操作数栈
操作数栈的深度在编译期已经决定,在方法的 Code 属性的 max_stacks 数据项中 -
动态链接(Dynamic Linking)
指向运行时常量池中栈帧所属方法的引用
用来支持方法调用中的动态连接。常量池的方法的符号引用,一部分在类加载的时候转化为直接引用,被称为静态解析。而动态连接指的是在每一次运行期间转化为直接引用 -
返回地址(Return Address)
正常返回,PC技术器的值作为返回地址保存
异常返回,通过异常处理表获得返回地址,栈帧一般不会保存这部分信息
设置虚拟机栈的大小
- -Xss
例如:-Xss128K
有两种异常
- StackOverflowError
- OutOfMemoryError
2.3 本地方法栈(Native Method Stack)
线程私有
为本地方法执行 Native 方法服务
2.4 Java 堆(Heap)
![](https://img.haomeiwen.com/i460263/e671f59ed5eb15d9.png)
特点:
- 线程共享
- 内存最大的一块
- 目的:存放对象实例 和 数组,但随着 JIT 的发展和逃逸分析技术成熟,栈上分配、标量替换,对象实例开始不一定分配在堆上
因为是 GC 回收的主要区域,根据 GC 的实现机制,会对堆进行分代
-
新生代(Young Generation)
Eden 新生的对象
Survivor Space 每次GC后还存活的对象,可再细分为 From Survivor 和 To Survivor -
老生代(Old Generation)
Tenured,存放生命周期长的对象
堆内存分配由 -Xmn 来指定
- -Xms,初始使用,默认物理内存 1/64
- -Xmx,最大内存,默认物理内存 1/4
例如:-Xms20m -Xmx20m
虚拟机会根据堆的空闲情况动态调整推大小,空余大于 70%,会减少到 -Xms,空余小于 40%,会增大到 -Xmx
所以服务器如果配置 -Xms = -Xmx,则可以避免堆自动扩展
新生代进行 minor GC,老生代进行 major GC(深度GC)。大部分GC发生在新生代中
2.5 方法区(Method Area)
特点:
- 线程共享
- 又称为 Non-Heap,用来和堆进行区分
- HotSpot 虚拟机把 GC 分代收集扩展至方法区,所以在 HotSpot 可以称它为永久代(Permanent Generation)
存储被虚拟机加载的内容有:
- 类信息
- 常量
- 静态变量
- 即时编译器编译后的代码
方法区包含运行时常量池,Class 文件的各种字面量和符号引用,在类加载后会存入到运行时常量池中。直接引用也会存储在运行时常量池。除了类加载阶段,运行时也可以动态加入,比如 String 的 intern() 方法
方法区的大小的分配
- -XX:MaxPermSize 最大值
- -XX:PermSize 最小值
例如:-XX:MaxPermSize=10M -XX:PermSize=10M
运行时方法区无法满足内存分配,也会抛出 OutOfMemoryError
3 直接内存
特点
- 不属于运行时数据区
- 不受 Java 堆大小的限制
JDK 1.4 的 NIO 可以直接使用 Native 函数直接分配这块内存,使用 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用
配置虚拟机参数需要考虑到这块内存,大小的分配
- -XX:MaxDirectMemorySize 最大值,默认和 Java 堆最大值一样
例如:-XX:MaxDirectMemorySize=10M
内存申请不到后也会抛出 OutOfMemoryError
网友评论