【JVM:一】Java运行时数据区域

tech2022-08-09  147

Java运行时数据区域

1 程序计数器(Program Counter Register)

线程私有。 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在多线程环境下,每条线程都需要一个独立的程序计数器,各个线程之间计数器互不影响,独立存储,所以将其设计为线程私有。 程序计数器不会发生OutOfMemeryError的错误情况。因为程序计算器所维护的就是下一条待执行的命令的地址,所以不存在OOM。

2 Java虚拟机栈(Java Virtual Machine Stack)

线程私有。 虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候Java虚拟机都会同步创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。 如果线程请求的栈深度大于虚拟机所允许的栈深度,将抛出StackOverFlowError异常。由于HotSpot不支持栈容量的动态扩容,所以只要线程成功的申请到了栈空间,就不会发生OOM,如果申请失败仍会OOM。

3 本地方法栈

线程私有。 与Java虚拟机栈的区别是,它是为虚拟机使用到本地方法服务。也会发生栈溢出异常和OOM。

4 Java堆

线程共享。 用于存放对象实例的内存区域。是垃圾收集器管理的内存区域。 如果在Java堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出OOM异常。

4.1 字符串常量池

JDK1.7之前,字符串常量池再永久代中。首次调用intern方法,会将改字符串复制到字符串常量池中,并返回池里的引用。 JDK1.7之后,字符串常量池移到了堆中。首次调用intern方法,如果字符串常量池中没有该串,就会在池中创建一个对该字符串的引用并返回。

5 方法区

线程共享。 方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。JDK7时,把原本放在永久代的字符串常量池、静态变量等移除,到了JDK8,完全废弃了永久代的概念,改为在本地内存中实现的元空间来代替。 相对而言,垃圾收集行为在这个区域的确是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。这区域的内存回收目标主要是针对常量池的回收和对类型的卸载。 当方法区无法满足新的内存分配需求时,将抛出OOM异常。

5.1 运行时常量池

运行时常量池是方法区的一部分。Class文件有一项信息是常量池表,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。 Java语言并不要求常量一定只有编译期才能产生,运行期间也可以将新的常量放入池中。如String类的intern()方法。 当常量池无法再申请到内存时会抛出OOM异常。

最新回复(0)