Java 虚拟机学习笔记 | 运行时数据区总结

前言

要想学习好 Java,Java虚拟(JVM)的学习是绕不开的。学习 Java虚拟(JVM)首先就要先了解的就是Java虚拟(JVM)运行时数据区。

Java语言和虚拟机规范中对运行时数据区进行了简单的说明,具体内容:Java虚拟机定义了在程序执行期间使用的各种运行时数据区域。其中一些数据区域是在Java虚拟机启动时创建的,仅在Java虚拟机退出时销毁。其他数据区域是每个线程私有的。线程数据区域是在线程创建时创建,线程销毁时销毁的。

那么上面所说的各种运行时数据区域如下:

  1. 程序计数器
  2. Java 虚拟机栈
  3. 本地方法栈
  4. 方法区
  5. 直接内存

该文介绍 带你了解上述6种运行时数据区的定义,作用、是否线程私有、生命周期,可能出现的异常。

准确来讲应该是5种运行时数据区,因为直接内存不属于虚拟机规范运行时数据区的内存。

程序计数器

程序计数器是记录当前线程正在执行的Java虚拟机指令一块内存空间,Java虚拟机指令包括:循环,跳转,异常处理等。在多线程运行中(Java 虚拟机多线程是轮流切换给处理器执行的)。可以保证线程切换后可以恢复到正确的执行位置。

程序计数器是线程私有,每个线程都有一个独立的程序计数器。生命周期与线程一致,是唯一一个没有 OutOfMemoryError 的区域。

需要注意的是:如果线程执行的是Java 方法,计数器保存的是 Java虚拟机指令。如果线程当前正在执行该方法 native,计数器保存的是空(Undefinde)

Java 虚拟机栈

Java 虚拟机栈是用来记录Java 方法执行过程的内存区域。当我们方法在创建时会创建一个栈帧用于存储局部变量,动态链接,方法出口等信息。方法的执行就是栈帧在Java 虚拟机栈中的入栈和出栈过程。

Java 虚拟机栈是线程私有的,生命周期和线程相同。Java 虚拟机栈中线程请求栈的深度大于虚拟机允许的深度将抛出StackOverflowError,如果扩展无法申请到足够的内存抛出 OutOfMemoryError 异常。

-Xss设置虚拟机栈的大小

本地方法栈

本地方法栈和Java 虚拟机栈一样,区别在于本地方法栈执行的是Native方法,而Java 虚拟机栈执行的是Java方法。

本地方法栈也会抛出StackOverflowError 和 OutOfMemoryError异常。

我们的Sun HotSopt 直接将本地方法栈和Java 虚拟机栈 合二为一。

堆也被成为GC 堆,用于存放对象实例内存区域。它是线程共享的,也是垃圾收集器管理主要区域。

堆内存在虚拟机启动时进行创建,Java虚拟机退出时销毁。如果堆中没有内存存放我们创建的实例,并且无法进行扩展时 会抛出 OutOfMemoryError 异常

方法区

方法区用来存储已加载类的信息,常量, 静态变量, 即时编译器编译后的代码的内存区域。也被称之为非堆和永久代。

方法区是线程共享的内存区域,该内存在虚拟机启动时进行创建,Java虚拟机退出时销毁。垃圾收集器主要对方法区中的类型卸载 和常量池的内存回收 。方法区无法满足内存分配时将抛出 OutOfMemoryError 异常

JDK1.8以前方法区的实现是永久代,JDK 1.8 将方法去移除了,通过元空间将其替代。

官方说明:
参照JEP122:http://openjdk.java.net/jeps/122,原文内容如下:
This is part of the JRockit and Hotspot convergence effort. JRockit customers do not need to configure the permanent generation (since JRockit does not have a permanent generation) and are accustomed to not configuring the permanent generation.
即: 移除永久代是为融合HotSpot JVM与 JRockit VM而做出的努力,因为JRockit没有永久代,不需要配置永久代。

元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。
摘抄自–余磊博客 JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)

运行时常量池

运行时常量池 是方法区的一部分 该区域用于存放编译器生成的各种字面量和符号引用。在类加载后存放到运行时常量池中。当常量池无法在申请到内存时抛出OutOfMemoryError 异常

直接内存

它不是java 虚拟机中规定的内存,但是容易被我们忽视。直接内存受我们的本机总内存的影响 如果 Java虚拟器内存过大 导致我们的直接内存无法扩展是会抛出 OutOfMemoryError 异常

JDK1.4 引入 NIO 通过通道与缓存的I/O方式 它可以使用Native 函数库直接分配的堆外内存 而这个存储就是我们直接内存。

参考文献

  • 深入理解Java虚拟机 JVM 高级特性与最佳实践
  • Java语言和虚拟机规范:https://docs.oracle.com/javase/specs/index.html
  • JDK8-废弃永久代(PermGen)迎来元空间(Metaspace):https://www.cnblogs.com/yulei126/p/6777323.html
发布了136 篇原创文章 · 获赞 502 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/ljk126wy/article/details/98472452
今日推荐