Java基础 Jvm如何加载类?如何分配空间?

  • Post author:
  • Post category:java


Java基础Jvm如何加载类?如何分配空间?指的是将 class 文件的二进制数据读入到运行时数据区(JVM在内存中划分的)中,并在方法区内创建一个 class 对象JVM 运行起来时就给内存划分空间,这块空间就称为运行时数据区。

运行时数据区被划分为以下几块内容:

1、栈:

每一个线程运行起来的时候就会对应一个栈(线程栈),栈中存放的数据被当前线程所独享不会产生资源共享情况,所以线程是安全的。

而栈当中存放的是栈帧,当线程调用方法时,就是形成一个栈帧,并将这个栈帧进行压栈操作。方法执行完后,进行出栈操作。这个栈帧里面包括局部变量,操作数栈,指向当前方法对应类的常量池引用,方法返回地址等信息。

2、本地方法栈:

本地方法栈的机制和栈的相似,区别在于,栈运行的是Java 实现的方法,而本地方法栈运行的是本地方法。本地方法指的是 JVM 需要调用非Java 语言所实现的方法,例如 C 语言。在 JVM 规范中,没有强化性要求实现方一定要划分出本地方法栈(例如:HotSpot 虚拟机将本地方法栈和栈合二为一)和具体实现(不同的操作系统,对 JVM规范的具体实现都不一样)。

3、程序计数器:

程序计数器也可以称为 PC 寄存器(通俗讲就是 指令缓存)。它主要用于缓存当前程序下一条指令的指令地址,CPU 根据这个地址找到将要执行的指令。这个寄存器是 JVM内部实现的,不是物理概念上的计数器,不过和 JVM 的实现逻辑一样。

4、堆:

堆内存主要存放创建的对象和数组。堆内存在 JVM 中是唯一的,能被多个线程所共享。堆里面的每一个对象都存放着实例的实例变量。堆内存的对象没有被引用,会自动被 Java垃圾回收机制回收。

当在方法中定义了局部变量,如果这个变量是基本数据类型,那么这个变量的值就直接存放在栈中;如果这个变量是引用数据类型,那么变量值就存放在堆内存中,而栈中存放的是指向堆中的引用地址。

5、方法区:

   方法区在 JVM 也是一个非常重要的一块内存区域,和堆一样,可以被多个线程多共享。

主要存放每一个加载 class 的信息。class 信息主要包含魔数(确定是否是一个 class 文件),常量池,访问标志(当前的类是普通类还是接口,是否是抽象类,是否被 public 修饰,是否使用了 final修饰等描述信息…),字段表集合信息(使用什么访问修饰符,是实例变量还是静态变量,是否使用了 final 修饰等描述信息…),方法表集合信息(使用什么访问修饰符,是否静态方法,是否使用了 final 修饰,是否使用了 synchronized 修饰,是否是native 方法…)等内容。当一个类加载器加载了一个类的时候,会根据这个 class 文件创建一个class 对象,class 对象就包含了上述的信息。

后续要创建这个类的实例,都根据这个 class 对象创建出来的。

6、常量池:

常量池是方法区中的一部分,存放 class 对象中最重要的资源。JVM 为每一个 class 对象都维护一个常量池。



版权声明:本文为qf2019原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。