JVM虚拟机结构

JVM的主要结构如下图所示,图片引用自舒の随想日记

JVM结构

方法区和堆由所有线程共享,其他区域都是线程私有的

程序计数器(Program Counter Register)

类似于PC寄存器,是一块较小的内存区域,通过程序计数器中的值寻找要执行的指令的字节码,由于多线程间切换时要恢复每一个线程的当前执行位置,所以每个线程都有自己的程序计算器。这一个区域不会有OutOfMemeryError。当执行Java方法时,这里存储的执行的指令的地址,如果执行的是本地方法,这里的值是Undefined。

虚拟机栈(Java Stack)

虚拟机栈也是线程私有的,每创建一个线程,虚拟机就会为这个线程创建一个虚拟机栈,虚拟机栈表示Java方法执行的内存模型,每调用一个方法,就会生成一个栈帧(Stack Frame)用于存储方法的本地变量表、操作栈、方法出口等信息,当这个方法执行完后,就会弹出相应的栈帧。

如果请求的栈的深度过大,虚拟机可能会抛出StackOverflowError异常,如果虚拟机的实现中允许虚拟机栈动态扩展,当内存不足以扩展栈的时候,会抛出OutOfMemoryError异常。

栈帧(Stack Frame)

栈帧分为三部分:局部变量区(Local Variables)、操作数栈(Operand Stack)和帧数据区(Frame Data)。

局部变量区(Loca Variables)

局部变量区被组织一个一个从0开始的字数组,byte、short、char在存储前被转换为int,boolean也被转换为int,0表示false,非0表示true,long和double占据两个字长。

操作数栈(Operand Stack)

操作数栈也被组织为一个字数组,但不同于局部变量区,它不是通过数组下标访问的,而是能过栈的Push和Pop操作,前一个操作Push进的数据可以被下一个操作Pop出来使用。

帧数据区(Frame Data)

这部分的作用主要有三部分:

  • 常量池中数据的解析
  • 方法执行完后处理方法返回,恢复调用方现场
  • 方法执行过程中抛出异常时的异常处理,存储有一个异常表,当出现异常时虚拟机查找相应的异常表看是否有对应的Catch语句,如果没有就抛出异常终止这个方法调用

本地方法栈(Native Method Stack)

与虚拟机栈类似,只是是执行本地方法时使用的。

方法区(Method Area)

用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译后的代码等信息。

方法区是线程间共享的,当两个线程同时需要加载一个类型时,只有一个类会请求ClassLoader加载,另一个线程会等待。

对于每一个加载的类型,会在方法区中保存以下信息:

  • 类及其父类的全限定名(java.lang.Object没有父类)
  • 类的类型(Class or Interface)
  • 访问修饰符(public, abstract, final)
  • 实现的接口的全限定名的列表
  • 常量池
  • 字段信息
  • 方法信息
  • 除常量外的静态变量
  • ClassLoader引用
  • Class引用

对于每一个字段,会在方法区中保存以下信息(字段声明顺序也会保存):

  • 字段名
  • 字段的类型
  • 字段的修饰符(public, private , protected, static, final, volatile, transient)

对于每一个方法,会在方法区中保存以下信息(方法声明顺序也会保存):

  • 方法名
  • 方法返回类型(或void)
  • 参数信息
  • 方法修饰符(public, private, protected , static, final, synchronized, native, abstract)

如果方法不是抽象方法并不是本地方法(Native Method),还会保存以下信息:

  • 方法的字节码
  • 本地变量表及操作数栈的大小
  • 异常表

虚拟机需要存储一些数据,用来快速地访问一个类对象中的方法,一般实现为一个方法表。

方法区中还有一部分是运行时常量池,主要用来存储编译时生成的字面量和符号引用,常量也可以在运行时产生,如String的intern方法。

方法区中也可能存在GC,但虚拟机规范对此不做要求,主要是回收一些常量和卸载一些不用的类型信息,不过要卸载一个类的条件很难达到,而且些处GC其实也回收不了多少内存。

堆(Heap)

虚拟机中用于存放对象与数组实例的地方,垃圾回收的主要区域就是这里(还可能有方法区)。

如果垃圾收集算法采用按代收集(目前大都是这样),这部分还可以细分为新生代和老年代。

新生代又可能分为Eden区,From Survivor区和To Survivor区,主要是为了垃圾回收。所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer,TLAB)。

Java堆只要求逻辑上是连续的,在物理空间上可以不连续。

直接内存

JDK1.4中引用了NIO,并引用了Channel与Buffer,可以使用Native函数库直接分配堆外内存,并通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。

对象访问

当新建一个对象时,会在堆中为这个对象分配内存,并在栈中有一个对这个对象引用,除此之外,在Java堆中还要能通过这个对象找到它的类型信息(对象类型,父类,实现的接口,包含的字段与方法等)。

Reference在Java虚拟机中定义为指向对象的引用,但没有定义这个Reference应该有怎么实现。

一种实现是Reference直接存储对象在堆内的地址,对象的类型信息可以在对象在堆中的内存布局中存储,如存储在对象内存的开头等。

另一种实现是Reference指向一个句柄表中的一个位置,句柄中保存了对象的实际位置及它对应的类型信息。

使用句柄的好处是当在内存中移动对象的位置时,只需要更新句柄表中的内容,不需要改变引用值,但会多一次内存访问开销,直接引用的优缺点与此相反。

参考资料:

  1. 深入Java虚拟机
  2. 深入理解Java虚拟机-JVM高级特性与最佳实践
  3. 浅析Java虚拟机结构与机制

JVM虚拟机结构,布布扣,bubuko.com

时间: 2024-11-04 14:15:44

JVM虚拟机结构的相关文章

读书笔记-深入理解JVM虚拟机-1.JVM-Stack造成的OOM的理解

-Xss128k:这个JVM参数用来配置栈的大小为128k 因为栈是线程私有的(不清楚的可以去了解下JVM虚拟机结构),所以如果我们启动一个线程,并且在这个线程中调用一个递归,就会产生该异常. /** * VM Args:-Xss128k * */ public class JavaVMStackSOF { private int stackLength = 1; public void stackLeak() { stackLength++; stackLeak(); } public sta

JVM内存结构

一.JVM内存结构 1.1 下面总体说说内存 Java虚拟机会将内存分为几个不同的管理区,这些区域各自有各自的用途,根据不同的特点,承担不同的任务以及在垃圾回收时运用不同的算法.总体分为下面几个部分: 程序计数器(Program Counter Register).JVM虚拟机栈(JVM Stacks).本地方法栈(Native Method Stacks).堆(Heap).方法区(Method Area) 1.2 下面说说具体各个结构的功能 1.2.1.程序计数器(Program Counte

JVM内存结构——运行时数据区

在Java虚拟机规范中将Java运行时数据划分为6种,分别为: PC寄存器(程序计数器) Java栈 堆 方法区 运行时常量池 本地方法栈 一.PC寄存器(程序计数器) PC寄存器(Program Counter Register)严格来说是一个数据结构,它用于保存当前正常执行的程序的内存地址. 线程私有. 每个线程启动的时候,都会创建一个PC(Program Counter,程序计数器)寄存器.PC寄存器里保存有当前正在执行的JVM指令的地址. 每个线程都需要一个独立的程序计数器,各条线程之间

jvm系列(二):JVM内存结构

原文出处:纯洁的微笑 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问题就会变的非常常见,了解JVM内存也是为了服务器出现性能问题的时候可以快速的了解那块的内存区域出现问题,以便于快速的解决生产故障. 先看一张图,这张图能很清晰的说明JVM内存结构布局. JVM内存结构主要有三大块:堆内存.方法区和栈.堆内存是JVM中最大的一块由年轻代和老年代组

JVM(虚拟机)原理

一.Java虚拟机的生命周期: Java虚拟机的生命周期 一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序.程序开始执行时他才运行,程序结束时他就停止.你在同一台机器上运行三个程序,就会有三个运行中的Java虚拟机. Java虚拟机总是开始于一个main()方法,这个方法必须是公有.返回void.直接受一个字符串数组.在程序执行时,你必须给Java虚拟机指明这个包换main()方法的类名. Main()方法是程序的起点,他被执行的线程初始化为程序的初始线程.程序中其他的线程都由他来

初谈JVM虚拟机

学了这么久的Java,一直听说JVM虚拟机是运行所有java程序,但是不知道具体内部结构是怎样,以及它的运行机制是什么.今天刚好看到一篇文章,索性就开始学习. JVM的主要结构: 由上图可以看出,Jvm主要组成有:类加载器.运行数据区.执行引擎.本地方法接口组成.其中运行数据区包含子模块方法区.堆.Java栈.本地方法栈以及寄存器.对于方法区.堆是对所有线程共享的,而其他则是属于当前线程私有. 下面开始一步步剖析JVM........... 1.类加载器(Class loader) 类加载器负责

Java虚拟机 - 结构原理与运行时数据区域

http://liuwangshu.cn/java/jvm/1-runtime-data-area.html 前言 本来计划要写Android内存优化的,觉得有必要在此之前介绍一下Java虚拟机的相关知识,Java虚拟机也并不是三言两语能够介绍完的,因此开了Java虚拟机系列,这一篇文章我们来学习Java虚拟机的结构原理与运行时数据区域. 1.Java虚拟机概述 Oracle官方定义的Java技术体系主要包括以下几个部分: Java程序设计语言 各种平台的Java虚拟机 Class文件格式 Ja

JVM虚拟机

JVM的主要结构如下图所示,图片引用自舒の随想日记. 方法区和堆由所有线程共享,其他区域都是线程私有的 程序计数器(Program Counter Register) 类似于PC寄存器,是一块较小的内存区域,通过程序计数器中的值寻找要执行的指令的字节码,由于多线程间切换时要恢复每一个线程的当前执行位置,所以每个线程都有自己的程序计算器.这一个区域不会有OutOfMemeryError.当执行Java方法时,这里存储的执行的指令的地址,如果执行的是本地方法,这里的值是Undefined. 虚拟机栈

java之jvm学习笔记十三(jvm基本结构)

java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成图形,所以只要你有耐心,仔细,认真,并发挥你的想象力,这一章之后你会充满自信.当然,不是说看完本章,就对jvm了解了,jvm要学习的知识实在是非常的多.在你看完本节之后,后续我们还会来学jvm的细节,但是如果你在学习完本节的前提下去学习,再学习其他jvm的细节会事半功倍. 为了让你每一个知识点都有迹