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个字


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

查看所有标签

猜你喜欢:

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

机器学习实践指南

机器学习实践指南

麦好 / 机械工业出版社 / 2014-4-1 / 69.00

《机器学习实践指南:案例应用解析》是机器学习及数据分析领域不可多得的一本著作,也是为数不多的既有大量实践应用案例又包含算法理论剖析的著作,作者针对机器学习算法既抽象复杂又涉及多门数学学科的特点,力求理论联系实际,始终以算法应用为主线,由浅入深以全新的角度诠释机器学习。 全书分为准备篇、基础篇、统计分析实战篇和机器学习实战篇。准备篇介绍了机器学习的发展及应用前景以及常用科学计算平台,主要包括统......一起来看看 《机器学习实践指南》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具