• JVM内存模型


    jvm内存模型

    1.执行过程

    Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间)。  

    2.运行时数据区分类

    方法区(特殊的堆):线程共享的内存区域,

    1、类型信息

    类型的全限定名
    超类的全限定名
    直接超接口的全限定名
    类型标志(该类是类类型还是接口类型)
    类的访问描述符(public、private、default、abstract、final、static)

    2、类型的常量池

    存放该类型所用到的常量的有序集合,包括直接常量(如字符串、整数、浮点数的常量)和对其他类型、字段、方法的符号引用。常量池中每一个保存的常量都有一个索引,就像数组中的字段一样。因为常量池中保存中所有类型使用到的类型、字段、方法的字符引用,所以它也是动态连接的主要对象(在动态链接中起到核心作用)。

    3、字段信息(该类声明的所有字段)

    字段修饰符(public、protect、private、default)
    字段的类型
    字段名称

    4、方法信息

    方法信息中包含类的所有方法,每个方法包含以下信息:

    方法修饰符
    方法返回类型
    方法名
    方法参数个数、类型、顺序等
    方法字节码
    操作数栈和该方法在栈帧中的局部变量区大小
    异常表

    5、类变量(静态变量)

    指该类所有对象共享的变量,即使没有任何实例对象时,也可以访问的类变量。它们与类进行绑定。

    6、 指向类加载器的引用

    每一个被JVM加载的类型,都保存这个类加载器的引用,类加载器动态链接时会用到。

    7、指向Class实例的引用

    类加载的过程中,虚拟机会创建该类型的Class实例,方法区中必须保存对该对象的引用。通过Class.forName(String className)来查找获得该实例的引用,然后创建该类的对象。

    8、方法表

    为了提高访问效率,JVM可能会对每个装载的非抽象类,都创建一个数组,数组的每个元素是实例可能调用的方法的直接引用,包括父类中继承过来的方法。这个表在抽象类或者接口中是没有的,类似C++虚函数表vtbl。

    常量池(方法区内)包含的内容:

    public class Demo{
    
    String s ="aaa";
    int a = 5;
    
    
    
    }//Demo,s,a,"aaa",都是常量

    JVM堆(Java Heap):
    Java 堆也是属于线程共享的内存区域,它在虚拟机启动时创建,是Java 虚拟机所管理的内存中最大的一块,主要用于存放对象实例,几乎所有的对象实例都在这里分配内存,注意Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做GC 堆,如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常。 

    虚拟机栈(Java Virtual Machine Stacks):

    Java虚拟机栈也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链表、方法出口信息等。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。  

    本地方法栈(Native Method Stacks):
    本地方法栈属于线程私有的数据区域,这部分主要与虚拟机用到的 Native 方法相关,一般情况下,我们无需关心此区域。

    程序计数器(Program Counter Register):
    字节码解释器工作时,通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
    多线程中,为了让线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间互不影响、独立存储,因此这块内存是线程私有的。 

     注意:final修饰的局部变量是存放在常量池中 

    对于通过new产生一个字符串(假设为”china”)时,会先去常量池中查找是否已经有了”china”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”china”对象的拷贝对象。这也就是有道面试题:String s = new String(“xyz”);产生几个对象?一个或两个,如果常量池中原来没有”xyz”,就是两个。 

     

  • 相关阅读:
    没提供编码格式,读文件时要怎么推测文件具体的编码
    Spring系列.@EnableRedisHttpSession原理简析
    程序员必备画图技能之——流程图
    痞子衡嵌入式:第一本Git命令教程(7.1)- 清理之缓存(stash)
    痞子衡嵌入式:第一本Git命令教程(6)- 日志(log/reflog/gitk)
    痞子衡嵌入式:第一本Git命令教程(5)- 提交(commit/format-patch/am)
    痞子衡嵌入式:第一本Git命令教程(4)- 转移(add/rm/mv)
    痞子衡嵌入式:第一本Git命令教程(3)- 变动(status/diff)
    痞子衡嵌入式:第一本Git命令教程(2)- 连接(remote/clone)
    痞子衡嵌入式:第一本Git命令教程(1)- 准备(init/config/.gitignore)
  • 原文地址:https://www.cnblogs.com/zkkkk-/p/10487916.html
Copyright © 2020-2023  润新知