JVM的结构

栏目: Java · 发布时间: 5年前

内容简介:结合《深入理解Java虚拟机:高级特性及最佳实践》、《实战Java虚拟机——JVM故障诊断与性能优化》、油管视频,下图是我对JVM结构的总结:要理解JVM的结构,其实可以从java程序怎么运行的角度去理解:java程序运行的是class文件,所以需要

结合《深入理解 Java 虚拟机:高级特性及最佳实践》、《实战Java虚拟机——JVM故障诊断与性能优化》、油管视频,下图是我对JVM结构的总结:

JVM的结构

要理解JVM的结构,其实可以从java程序怎么运行的角度去理解:

java程序运行的是class文件,所以需要 类装载子系统 来把class文件加载到内存中运行,而class文件具体是加载存放到jvm中一块叫 方法区 的内存空间,方法区除了存放类信息外,还划分了一块叫 运行时常量池 的区域,用来存放字符串字面量、数字常量等信息。

class文件加载了,内存中有类信息了,java程序中就可以创建对象。那么对象又存哪里?当然是我们耳熟能详的 堆内存 了。另外,除了堆内存,还有一块 直接内存 ,这块内存是堆外的内存,是直接向系统申请的内存空间,这块内存访问速度比堆内存块,比如Java的NIO库就使用了直接内存。

上面几样都是跟 程序的数据存储 相关的,而程序需要实现运行,以下的就是相关的:

Java栈:Java是多线程的,一条运行的线程就会有一个对应的Java栈。而一个线程跑的程序,会调用很多的函数,一个函数就对应Java栈中一个 栈帧 。栈帧存放着函数运行需要的东西,栈帧包含了: 局部变量表操作数栈帧数据区 等等。 帧数据区 是用来支持栈帧做常量池解析、方法返回、异常处理的。比如当Java字节码需要访问常量池时,帧数据区保存则常量池的指针,方便程序访问常量池;比如异常处理,帧数据区中会有一个异常处理表,方便在发生异常时找到处理异常的代码。

Exception table:
from    to  target  type
4       16  19      any
19      21  19      any
复制代码

上面的异常处理表,表示字节码偏移量4~16字节可能抛出异常,如果抛出异常,跳转到偏移量19的地方继续执行。

程序计数器:英文名是Program Counter Register,直译是“程序计数器寄存器”,所以国内的博客、书籍叫法有些统一。有的叫“程序计数器”,有的叫“PC寄存器”。我这里参考《深入理解Java虚拟机-JVM高级特性与最佳实践》的表述方法,叫程序计数器。 程序计数器就是用来记录线程当前执行到哪一行字节码的。

本地方法栈:结构跟Java栈差不多,区别就是它是用来执行本地方法的。

以上的 方法区、Java堆、程序计数器、Java栈、本地方法栈 构成了JVM的 运行时数据区

有了 运行时数据区 来存放Java程序运行的所有数据,就可以用 执行引擎 来把程序执行跑起来了。比如 Interpreter 是解析器,用来读取执行字节码的指令; JIT Compiler 是即时编译器,可以即时把字节码指令编译机器码,弥补了Interpreter的性能不足; GC 就是垃圾收集器,用来收集在运行时产生的垃圾内存。

关于局部变量表的一个细节

我在看《实战Java虚拟机-JVM故障诊断与性能优化》时看到一些有趣的地方,做了测试,顺便记录下来。

细节1:不同编译器编译出来局部变量表的大小有可能不一样。

public class TestStackDeep {
    private static int count = 0;

    public static void recursion(long a, long b, long c) {
        long e = 1, f = 2, g = 3, h = 4, i = 5, k = 6, q = 7, x = 8, y = 9, z = 10;
        count++;
        recursion(a, b, c);
    }
    public static void main(String args[]) {
        try {
			recursion(0L,0L,0L);
        } catch (Throwable e) {
            System.out.println("deep of calling = " + count);
            e.printStackTrace();
        }
    }
}
复制代码

上面代码中的recursion方法,有3个long类型的形参,方法中还定义了10个局部变量。在Intellij IDEA中使用 jclasslib的插件 可以查看到这个方法的局部变量表的大小:

这里是在Intellij IDEA中使用jdk7的javac编译器编译出来的,局部变量表占26个字:

JVM的结构
JVM的结构
JVM的结构

改成eclipse编译器后,局部变量表占6个字:

JVM的结构
JVM的结构

看来eclipse编译器是做了优化,在recursion方法中定义的10个局部变量都没有使用过,所以直接就去掉了,只剩下6个字

“字”是指计算机内存中占据的一个单独的内存单元编号的一组二进制串。一般32位计算机上一个字为4个字节长度

细节2:局部变量表的槽位

public class LocalVar {
    public void localvar1() {
        int a = 0;
        System.out.println(a);
        int b = 0;
    }

    public void localvar2() {
        {
            int a = 0;
            System.out.println(a);
        }
        int b = 0;
    }

    public static void main(String[] args) {

    }
}
复制代码

还是使用jclasslib来查看局部变量表。其中,

localvar1的局部变量表(最大占3个字):

JVM的结构

localvar1的局部变量表(最大占2个字):

JVM的结构

注意看localvar1的Index列显示占的槽位是0,1,2三个槽位,一个槽位占一个字,所以localvar1的局部变量表最大占3个字;

而注意看localvar2的Index列显示占的槽位是1,0,1,其中槽位“1”复用了,这叫叫 槽位复用 ,所以localvar2的局部变量表最大占2个字


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First HTML and CSS

Head First HTML and CSS

Elisabeth Robson、Eric Freeman / O'Reilly Media / 2012-9-8 / USD 39.99

Tired of reading HTML books that only make sense after you're an expert? Then it's about time you picked up Head First HTML and really learned HTML. You want to learn HTML so you can finally create th......一起来看看 《Head First HTML and CSS》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码