Java核心:类加载和JVM内存的分配

Posted Hmake

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java核心:类加载和JVM内存的分配相关的知识,希望对你有一定的参考价值。

 

类的加载:

  指的是将class文件的二进制数据读入到运行时数据区(JVM在内存中划分的)

中,并在方法区内创建一个class对象。

类加载器:

  负责加载编译后的class文件(字节码文件)到JVM(Java虚拟机)当中。

而类加载器主要分为以下几种:

1.Bootstrap class loader (引导类加载器)

  负责加载Java核心类库。在jre\lib目录下,包括rt.jar(Java基础类库),这些

都是Java的核心类库。而且这个加载器是由C语言编写的,所以在Java程序中是获取

不到的。

2.Extension class loader(扩展类加载器)

  负责加载Java平台下扩展功能的jar包,这些jar包在jre\lib\ext目录下。这个加载

器由Java语言编写的。

3.System class loader(系统类加载器)

  负责加载classpath目录下的所有类库,classpath目录下的class文件一般

是我们自己写的java文件编译后的。而这个加载器是由Java语言写的。

 

这些类加载器协同起来完成整个类的加载过程,因此这些类的加载模式基于

”双亲委托模型“。

 

双亲委托模型“:

  程序运行后,编译器把Java文件编译成class文件后,首先负责加载的是

系统类加载器,但它不会马上加载,而是将此任务移送给它的父类加载器扩展

类加载器加载,扩展类加载器也是将此任务移送给引导类加载器加载。

  class文件到了引导类加载器那,它先判断能不能加载这个类,如果能,就

加载;不能,移送给其子加载器,以此类推。最终我们编写的class都会配置在

classpath环境中,所以,这个类加载任务还是由系统类加载器完成。如果系统

类加载器都不能加载,就抛出ClassNotFoundException。

 

当一个class加载到JVM中,类加载阶段已经完成。接下来JVM分配内存,对整个

class文件(文件里面都是二进制的汇编命令)进行内容解析(JVM对二进制的命

令逐行解析,交由CPU执行)。

 

内存分配:

  JVM运行起来时就给内存划分空间,这块空间就称为运行时数据区。

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

1.栈:

  每一个线程运行起来的时候就会对应一个栈(线程栈),栈中存放的数据被当前

线程所独享(不会产生资源共享情况,所以线程是安全的)。而栈当中存放的是栈帧,

当线程调用方法时,就是形成一个栈帧,并将这个栈帧进行压栈操作。方法执行完后,

进行出栈操作。这个栈帧里面包括(局部变量,操作数栈,指向当前方法对应类的常

量池引用,方法返回地址等信息)。

2.本地方法栈:

  本地方法栈的机制和栈的相似,区别在于,栈运行的是Java实现的方法,而本地

方法栈运行的是本地方法。本地方法指的是JVM需要调用非Java语言所实现的方法,

例如C语言。在JVM规范中,没有强化性要求实现方一定要划分出本地方法栈(例如:

HotSpot虚拟机将本地方法栈和栈合二为一)和具体实现(不同的操作系统,对JVM

规范的具体实现都不一样)。

3.程序计数器:

  程序计数器也可以称为PC寄存器(通俗讲就是  指令缓存)。它主要用于缓存当前

程序下一条指令的指令地址,CPU根据这个地址找到将要执行的指令。这个寄存器是JVM

内部实现的,不是物理概念上的计数器,不过和JVM的实现逻辑一样。

4.堆:

  堆内存主要存放创建的对象和数组。堆内存在JVM中是唯一的,能被多个线程所共享。

堆里面的每一个对象都存放着实例的实例变量。

  当在方法中定义了局部变量,如果这个变量是基本数据类型,那么这个变量的值就直接

存放在栈中;如果这个变量是引用数据类型,那么变量值就存放在堆内存中,而栈中存放的是

指向堆中的引用地址。

5.方法区:

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

主要存放每一个加载class的信息。class信息主要包含魔数(确定是否是一个class文件),常量

池,访问标志(当前的类是普通类还是接口,是否是抽象类,是否被public修饰,是否使用了final

修饰等描述信息......),字段表集合信息(使用什么访问修饰符,是实例变量还是静态变量,是否

使用了final修饰等描述信息.....),方法表集合信息(使用什么访问修饰符,是否静态方法,是否

使用了final修饰,是否使用了synchronized修饰,是否是native方法......)等内容。当一个类加

载器加载了一个类的时候,会根据这个class文件创建一个class对象,class对象就包含了上述的信息。

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

6.常量池:

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

常量池。它主要存储两种类型的常量:

1.字面常量:

  字面常量通常就是在Java中定义的字面量值。例如:int = 1,中的 1,String s = "hello",这个

hello就是字面量。或者使用final修饰的常量值。

2.符号引用:

  符号引用主要包括类和接口的完整类名,属性的名称和描述符,方法名和描述符等。

 

 

-----------------------------------------------------------

以上是关于Java核心:类加载和JVM内存的分配的主要内容,如果未能解决你的问题,请参考以下文章

JVM内存模型和类加载运行机制

JVM核心机制_类加载的全过程_java的内存分析_初始化时机。

java核心学习(三十七) 类加载器

Java基础学习笔记二十三 Java核心语法之反射

醒酒菜:动画图解核心内存区--堆

#yyds干货盘点# 醒酒菜:动画图解核心内存区--堆