虚拟机内存区域
程序计数器
-
当前线程所执行的字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值来确定下一条要执行的字节码指令的位置
-
执行 Java 方法和 native 方法时的区别:
- 执行 Java 方法时:记录虚拟机正在执行的字节码指令地址;
- 执行 native 方法时:无定义(Undefined);
-
是 5 个区域中唯一不会出现 OOM (内存溢出)的区域。
例如:多线程,有两个线程,其中一个线程可以暂停使用,让其他线程运行,然后等自己获得cpu资源时,又能从暂停的地方开始运行,那么为什么能够记住暂停的位置的,这就依靠了程序计数器
作用:因为CPU需要不停地切换各个线程,这个时候切换回来的时候,就得知道接着从哪个位置继续执行。
为什么是线程私有?
为了准确地记录各个线程正在执行的当前字节码指令位置。
Java 虚拟机栈
-
虚拟机栈描述的是Java方法执行的内存模型,每个方法执行的过程,就是它所对应的栈帧在虚拟机栈中入栈到出栈的过程;
-
服务于 Java 方法;
-
可能抛出的异常:
- OutOfMemoryError(在虚拟机栈可以动态扩展的情况下,扩展时无法申请到足够的内存);
- StackOverflowError(线程请求的栈深度 > 虚拟机所允许的深度);
-
虚拟机参数设置:
-Xss
.
package MyDemo.work;
public class StackTest {
private void tes(){
System.out.println("方法执行");
tes(); //一直调用,未释放资源,造成内存溢出;只进栈。。。
}
public static void main(String[] args) {
new StackTest().tes();
}
}
//--------------------------
方法执行
方法执行
方法执行
Exception in thread "main" java.lang.StackOverflowError
at java.base/sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:564)
at java.base/java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:576)
本地方法栈
- 为虚拟机执行 native 方法服务;
- 可能抛出的异常:与 Java 虚拟机栈一样。
HotSpot(本地方法栈与虚拟机栈以合二为一)
Java堆
- 唯一的目的:存放对象实例;
- 垃圾收集器管理的主要区域;
- 可以处于物理上不连续的内存空间中;
- 可能抛出的异常:
- OutOfMemoryError(堆中没有内存可以分配给新创建的实例,并且堆也无法再继续扩展了)。
虚拟机参数设置:
- 最大值:
-Xmx
- 最小值:
-Xms
- 两个参数设置成相同的值可避免堆自动扩展。
方法区
-
存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;
- 类的版本,字段,方法,接口。
-
方法区与永久代
-
垃圾收集行为在此区域很少发生;
-
运行时常量池也是方法区的一部分;
- Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项是常量池,用于存放编译器生成的各种字面量(就是代码中定义的 static final 常量)和符号引用,这部分信息就存储在运行时常量池中。
-
可能抛出的异常:
- OutOfMemoryError(方法区无法满足内存分配需求时)。
运行时常量池:在编译后期生成的是各种字面量(字面量的意思就是值,比如int i=3,这个3就是字面量的意思)和符号引用,这些是存放在一个叫做常量池(这个常量池是在字节码文件中)的地方,当类加载进入方法区时,就会把该常量池中的内容放入运行时常量池中。这里要注意,运行时常量池和常量池,不要搞混淆了,字节码文件中也有常量池,在后面的章节会详细讲解这个东西。现在只需要知道方法区中有一个运行时常量池,就是用来存放常量的。还有一点,运行时常量池不一定就一定要从字节码常量池中拿取常量,可能在程序运行期间将新的常量放入池中,比如String.intern()方法,这个方法的作用就是:先从方法区的运行时常量池中查找看是否有该值,如果有,则返回该值的引用,如果没有,那么就会将该值加入运行时常量池中。
直接内存
-
JDK 1.4 的 NIO 类可以使用 native 函数库直接分配堆外内存,这是一种基于通道与缓冲区的 I/O 方式,它在 Java 堆中存储一个 DirectByteBuffer 对象作为堆外内存的引用,这样就可以对堆外内存进行操作了。因为可以避免 Java 堆和 Native 堆之间来回复制数据,在一些场景可以带来显著的性能提高。
-
虚拟机参数设置:
-XX:MaxDirectMemorySize
- 默认等于 Java 堆最大值,即
-Xmx
指定的值。
- 默认等于 Java 堆最大值,即
-
将直接内存放在这里讲解的原因是它也可能会出现 OutOfMemoryError;
- 服务器管理员在配置 JVM 参数时,会根据机器的实际内存设置
-Xmx
等信息,但经常会忽略直接内存(默认等于-Xmx
设置值),这可能会使得各个内存区域的总和大于物理内存限制,从而导致动态扩展时出现 OOM。
- 服务器管理员在配置 JVM 参数时,会根据机器的实际内存设置