美文网首页Java篇
JVM内存管理

JVM内存管理

作者: w达不溜w | 来源:发表于2022-03-31 23:09 被阅读0次

    1.JVM与操作系统的关系

    jvm与操作系统的关系.png

      JVM全称Java Virtual Machine(Java虚拟机)。JVM屏蔽了与具体操作系统平台(Linux、Windows、MacOS等)相关信息,使Java程序只需要生成JVM上运行的目标代码(字节码),就可以在多种不同平台上运行。JVM在执行字节码时,会把字节码翻译成具体平台上的机器指令(机器语言010101),这就是JVM的跨平台特征。JVM只识别字节码,像Kotlin、Groovy、Jruby等语言,他们也能编译成字节码,所以也能在JVM上跑,这个就是JVM的跨语言特征。

    2.Java SE 体系架构

    JVM只是一个翻译,在不同操作系统中运行,需要依赖于Java SE体系架构
    https://docs.oracle.com/javase/8/docs/

    java se体系图.png

    3.JVM整体

    jvm运行过程.png

      .java文件经过javac编译成.class(字节码),Java类加载器把字节码加载到JVM的运行时数据区(JVM管理的内存),执行引擎把运行时数据区的数据进行执行。

    运行时数据区

    运行时数据区.png

    自动化内存管理

    定义:Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。
    类型:程序计数器、虚拟机栈、本地方法栈、Java堆、方法区(运行时常量池)、直接内存。
    线程隔离数据区:也叫线程私有区,在jvm中运行多个线程,每个线程都有虚拟机栈、本地方法栈、程序计数器。
    方法区: 放class 、静态变量、常量
    堆:几乎所有的对象都在堆中分配

    ①程序计数器

    指向当前线程正在执行的字节码指令的地址。

    /**
     * @author Sun
     * 栈帧执行对内存区域的影响
     */
    public class Test {
    
        public int work(){//在运行过程中,打包一个栈帧
            int x=1;//x是一个局部变量
            int y=2;
            int z=(x+y)*10;
            return z;
        }
    
        public static void main(String[] args) {
            Test test=new Test();
            test.work();
        }
    }
    

    Android studio查看字节码:Preferences—>Tools—>External Tools 添加External Tools,添加好后保存。使用:右键.java文件—>External Tools—>Show Byte Code。

    show byte code.png

    如图配置:Name、Program、Arguments、Working directory
    Show Byte Code (这个自己命名就好)
    $JDKPath$\bin\javap
    -c -verbose $FileClass$
    $OutputPath$

    我们来看一下上面的work方法的字节码片段:

    public int work();
        descriptor: ()I
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=4, args_size=1
             0: iconst_1                    //将int类型1入操作数栈
             1: istore_1                    //将操作数栈中栈顶int类型数值,存入局部变量表(下标为1的位置)
             2: iconst_2                    //将int类型2入操作数栈
             3: istore_2                    //将操作数栈中栈顶int类型数值,存入局部变量表(下标为2的位置)
             4: iload_1                     //将局部变量表中下标为1的int类型数据入栈
             5: iload_2                     //将局部变量表中下标为2的int类型数据入栈
             6: iadd                        //1.将栈顶2个int类型数值出栈  2.相加    3.将结果压入操作数栈
             7: bipush        10            //10的值扩展成int值入操作数栈
             9: imul                        //1.将栈顶2个int类型数值出栈  2.相乘    3.将结果压入操作数栈
            10: istore_3                    //将操作数栈中栈顶int类型数值,存入局部变量表(下标为3的位置)
            11: iload_3                     //将局部变量表中下标为3的int类型数据入栈
            12: ireturn
              
            ...
    

    字节码code行号,针对work方法体的偏移量。

    简单理解为:程序计数器,记录字节码的地址。

    为什么需要程序计数器?时间片轮转机制,线程在执行的时候被切出去了,记录一下执行到哪里了

    程序计数器是JVM内存区域中唯一不会OOM,因为程序计数器是一块很小的区域,只需要记录地址,int类型就够了。

    ②虚拟机栈

    存储当前线程运行方法所需的数据,指令、返回地址。

    每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个的栈帧,对应着一次次的Java方法调用。

    栈帧:

    栈帧.png

    在每个Java方法被调用的时候,都会创建一个栈帧,并入虚拟机栈,一旦完成相应的调用,则出栈。

    每个栈帧包含四个区域:局部变量表、操作数栈、动态连接、返回地址

    • 局部变量表:用来存放局部变量的(8大基本数据类型和引用类型)
    • 操作数栈:用来存放方法执行的操作数的,参与计算的数据会频繁的入栈和出栈。(基于解释执行)
    • 动态连接:多态,运行时才能确定具体的方法
    • 完成出口:正常返回(调用程序计数器中的地址作为返回),异常(通过异常处理表来确定)

    ③本地方法栈

    本地方法栈保存的是native方法的信息
    当一个JVM创建的线程调用native方法后,JVM不再为其在虚拟机栈中创建栈帧,JVM只是简单的动态链接并直接调用native方法。

    相关文章

      网友评论

        本文标题:JVM内存管理

        本文链接:https://www.haomeiwen.com/subject/pvthlltx.html