jvm深入研究文档--jvm分区以及职责

Java虚拟机(JVM)主要包括以下几个区域:

  1. 方法区(Method Area):这个区域存储已被加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。方法区是所有线程共享的。在Java 8之前,方法区是永久代(PermGen),从Java 8开始,永久代被元空间(Metaspace)替代。
  2. 堆区(Heap):这是Java内存中最大的一块区域,被所有线程共享,用于存放对象实例。JVM在JDK 1.7之前,使用的是分代收集(Generational Collection),包括新生代(Young Generation)和老年代(Old Generation)。在JDK 1.8之后,引入了Eden Space, Survivor Space和Old Generation的概念。
  3. 栈区(Stack):每个线程在创建时都会创建一个虚拟机栈,每一个方法执行的时候都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
  4. 程序计数器(Program Counter Register):这个区域可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
  5. 本地方法栈(Native Method Stack):与虚拟机栈所发挥的作用非常相似,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。

每个JVM分区在不同版本的Java中都可能有所变更,特别是在每次大版本更新时,例如Java 8、Java 11和Java 17中都进行了一些重要的变更。

方法区(Method Area)

方法区(Method Area)是Java虚拟机(JVM)中的一部分,它与Java堆一样,是各个线程共享的内存区域。在JVM启动时方法区被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。

虽然方法区在逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。对于HotSpotJVM而言,方法区还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开。因此,方法区可以看作是一块独立于Java堆的内存空间。

此外,方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误。

堆区(Heap)

堆区是Java虚拟机(JVM)中的主要部分,也是垃圾收集的主要区域。它主要用于存放对象实例以及大多数Java对象(如数组,用户定义的类等)。

在Java堆中,对象的内存分配和回收是主要发生的地方。当你创建一个新的对象实例时,JVM会在堆上为其分配内存。当对象不再被引用时,垃圾收集器会回收其占用的内存。

Java堆是所有线程共享的,因此它是一个并发区域,也就是说在任何时刻,多个线程可能同时对同一个对象进行操作。

Java堆是垃圾收集的主要区域,这意味着垃圾收集器可以自动回收不再被引用的对象占用的内存。这极大地减少了内存泄漏的可能性,因为JVM会自动管理内存,避免内存泄漏。

栈区(Stack)

栈区是Java虚拟机(JVM)中的另一个重要部分,与堆区不同的是,栈区只属于某一个特定的线程,是线程私有的。每个线程都会有一个对应的栈,它的生命周期与线程的生命周期一致。

栈区主要用于执行Java方法,每一个方法的执行都会创建一个栈帧,用于存储局部变量、操作数栈以及动态链接和方法出口等信息。当一个方法执行完成后,对应的栈帧就会被弹出,所占用的内存会被释放。

栈区的容量也是有限制的,如果程序中创建了大量的栈帧并且没有被及时回收,那么就会出现栈溢出的情况,这时候程序会抛出一个StackOverflowError错误。在Java中,可以通过-Xss参数来设置每个线程的栈大小。

程序计数器(Program Counter Register)

程序计数器(Program Counter Register)是计算机处理器中的一种特殊寄存器。它的主要功能是跟踪并存储当前正在执行的指令在内存中的地址。

在计算机的执行过程中,程序计数器会根据指令的执行顺序进行更新。每执行一条指令,程序计数器就会增加,指向下一条要执行的指令。当遇到跳转指令(如JMP,CALL等)时,程序计数器会直接跳转到指定的地址,改变当前执行顺序。

程序计数器通常被视为CPU的"眼睛",它知道下一步应该执行哪条指令,是CPU执行流程的关键部分。

PC寄存器是线程私有的,每一个线程都有一个独立的PC寄存器。它的生命周期和线程保持一致,随着线程的创建和销毁而存在。

在JVM中,PC寄存器也是线程私有的,它用来存储JVM字节码指令的地址。JVM的字节码解释器通过改变PC寄存器的值来明确下一条要执行的字节码指令。

PC寄存器的设定是为了能够准确的记录各个线程正在执行的当前字节码指令地址,以便CPU在需要在线程之间切换时,可以快速准确地找到下一条要执行的指令。

本地方法栈(Native Method Stack)

本地方法栈(Native Method Stack)是Java虚拟机(JVM)中的一部分,与Java堆和栈区一起构成了Java运行时环境。

本地方法栈和Java栈一样,都是线程私有的,它用于支持native方法的执行。在Java中,如果一个方法使用了native修饰符,那么这个方法就会在本地方法栈中执行。

本地方法栈和Java栈的主要区别在于,本地方法栈中的方法可以执行操作系统级别的调用,例如访问文件系统、网络资源等。因此,本地方法栈具有更高的灵活性和更大的风险,因为它可以直接访问物理资源。

本地方法栈的管理和垃圾收集方式与Java堆和栈区不同,它的回收和内存管理需要更复杂的技术来实现。如果本地方法栈中的内存泄漏或者溢出,会对整个JVM的性能产生影响。

相关推荐
学点东西吧.41 分钟前
JVM(五、垃圾回收器)
jvm
请你打开电视看看3 小时前
Jvm知识点
jvm
程序猿进阶4 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
阿龟在奔跑15 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
王佑辉16 小时前
【jvm】方法区常用参数有哪些
jvm
王佑辉16 小时前
【jvm】HotSpot中方法区的演进
jvm
Domain-zhuo16 小时前
什么是JavaScript原型链?
开发语言·前端·javascript·jvm·ecmascript·原型模式
Theodore_10222 天前
7 设计模式原则之合成复用原则
java·开发语言·jvm·设计模式·java-ee·合成复用原则
我是苏苏2 天前
Web开发:ORM框架之使用Freesql的DbFrist封装常见功能
java·前端·jvm
天草二十六_简村人2 天前
Java语言编程,通过阿里云mongo数据库监控实现数据库的连接池优化
java·jvm·数据库·mongodb·阿里云·微服务·云计算