谈谈JVM类加载机制与内存模型

1、类加载机制

1.1、什么是类加载机制

我的理解是Java编译器将java文件编译成字节码文件,然后类加载器将字节码文件加载进JVM,放到对应内存区域中

1.2、类加载的生命周期

生命周期

类加载的生命周期是从类被加载到内存开始,直到卸载出内存为止的。整个生命周期分为7个阶段:加载、验证、准备、解析、初始化、使用、卸载。其中,验证、准备、解析三部分统称为连接。

  1. 加载:查找和导入Class文件;
  2. 连接:把类的二进制数据合并到JRE中;
    • 校验:检查载入Class文件数据的正确性;
    • 准备:给类的静态变量分配存储空间;
    • 解析:将符号引用转成直接引用;
  3. 初始化:对类的静态变量,静态代码块执行初始化操作。

1.3、类加载器

把类加载阶段的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作交给虚拟机之外的类加载器来完成。这样的好处在于,我们可以自行实现类加载器来加载其他格式的类,只要是二进制字节流就行,这就大大增强了加载器灵活性。系统自带的类加载器分为三种:

  1. 启动类加载器。(BootStrap ClassLoader)
  2. 扩展类加载器。(Extension ClassLoader)
  3. 应用程序类加载器。(Application ClassLoader)

1.4、双亲委派机制

双亲委派

双亲委派这个词听起来比较高深,其实就是如字面意思所示,如果一个类加载器收到了类加载器的请求.它首先不会自己去尝试加载这个类。而是把这个请求委派给父加载器去完成.每个层次的类加载器都是如此。因此所有的加载请求最终都会传送到Bootstrap类加载器(启动类加载器)中。只有父类加载反馈自己无法加载这个请求(它的搜索范围中没有找到所需的类)时。子加载器才会尝试自己去加载。
双亲委派模型的优点:java类随着它的加载器一起具备了一种带有优先级的层次关系。


2、内存模型

2.1、什么是Java内存模型

Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保证效果一致的机制及规范。

简要言之,jmm是jvm的一种规范,定义了jvm的内存模型。它屏蔽了各种硬件和操作系统的访问差异,不像c那样直接访问硬件内存,相对安全很多,它的主要目的是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。可以保证并发编程场景中的原子性、可见性和有序性。

根据java虚拟机规范,java虚拟机管理的内存将分为下面五大区域。

内存模型

2.2、五大内存区域简析

程序计数器

程序计数器是一块很小的内存空间,它是线程私有的,可以认作为当前线程的行号指示器。

注意:如果线程执行的是个java方法,那么计数器记录虚拟机字节码指令的地址。如果为native【底层方法】,那么计数器为空。这块内存区域是虚拟机规范中唯一没有OutOfMemoryError的区域。

Java栈(虚拟机栈)

同计数器也为线程私有,每个方法被执行的时候都会创建一个栈帧用于存储局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用的过程就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。

image

Java虚拟机栈可能出现两种类型的异常:
1、线程请求的栈深度大于虚拟机允许的栈深度,将抛出StackOverflowError。
2、虚拟机栈空间可以动态扩展,当动态扩展是无法申请到足够的空间时,抛出OutOfMemory异常。

本地方法栈

本地方法栈是与虚拟机栈发挥的作用十分相似,区别是虚拟机栈执行的是Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的native方法服务,可能底层调用的c或者c++,我们打开jdk安装目录可以看到也有很多用c编写的文件,可能就是native方法所调用的c代码。

对于大多数应用来说,堆是java虚拟机管理内存最大的一块内存区域,因为堆存放的对象是线程共享的,所以多线程的时候也需要同步机制。

注意:它是所有线程共享的,它的目的是存放对象实例。同时它也是GC所管理的主要区域,因此常被称为GC堆,又由于现在收集器常使用分代算法,Java堆中还可以细分为新生代和老年代,再细致点还有Eden(伊甸园)空间之类的不做深究。
根据虚拟机规范,Java堆可以存在物理上不连续的内存空间,就像磁盘空间只要逻辑是连续的即可。它的内存大小可以设为固定大小,也可以扩展。
当前主流的虚拟机如HotPot都能按扩展实现(通过设置 -Xmx和-Xms),如果堆中没有内存内存完成实例分配,而且堆无法扩展将报OOM错误(OutOfMemoryError)

方法区

方法区同堆一样,是所有线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量(常量池)、静态变量,如static修饰的变量加载类的时候就被加载到方法区中。

参考:
深入理解JVM-内存模型(jmm)和GC

浅析JVM类加载机制

类加载机制-深入理解jvm

你可能感兴趣的:(谈谈JVM类加载机制与内存模型)