JVM类加载

简介:

一、类加载器

1、什么是类加载器

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。完成类加载的家伙就是类加载器。

2、都有哪些类加载器

                    ClassLoader loader=Test01.         (loader!=              loader=loader.getParent();    }

结果:

  sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null

由输出结果可以看出ExtClassLoader是AppClassLoader的父类,而ExtClassLoader的父类却是null,原因是ExtClassLoader的父类加载器是BootStrap,BootStrap是JVM最底层的引导类加载器用C语言编写的,所以找不到一个确定的返回父Loader的方式,于是就返回null。

为什么要有这个引导类加载器:

  类加载器也是java类,他们也需要类加载器加载进入内存,显然必须要有第一个不是java类的类加载器,来完成这个工作,这个正是BootStrap。

JVM中类加载器的结构:

3、各个类加载器的作用

BootStrap  ClassLoader(启动类加载器):负责加载存放在D:\Program Files (x86)\Java\jdk1.7.0_79\jre\lib下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类均被Bootstrap ClassLoader加载)。启动类加载器是无法被Java程序直接引用的。

Extension ClassLoader(扩展类加载器):该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载D:\Program Files (x86)\Java\jdk1.7.0_79\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器。

Application ClassLoader(应用程序类加载器):该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

4、JVM类加载机制(JVM需要加载一个类时,到底会派出哪个类加载器去执行?)

全盘负责,当前线程的类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用CLassLoader.loadClass()指定类加载器来载入

父类委托,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。所以我们在开发中尽量不要使用与JDK相同的类(例如自定义一个java.lang.System类),因为父类加载器中已经有一份java.lang.System类了,它会直接将该类给程序使用,而你自定义的类压根就不会被加载。

123、如果BootStrap ClassLoader加载失败(例如在$JAVA_HOME/jre/4、若ExtClassLoader也加载失败,则会使用AppClassLoader来加载,如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException。

双亲委派模型意义:

  -系统类防止内存中出现多份同样的字节码

  -保证Java程序安全稳定运行

缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效。

5、自定义类加载器

 二、类的加载

1、类的加载:

  类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

字节码(.class)文件来源:

– 从本地系统中直接加载
– 通过网络下载.class文件
– 从zip,jar等归档文件中加载.class文件 
– 从专有数据库中提取.class文件
– 将Java源文件动态编译为.class文件

 

2、类加载的过程

JVM将javac编译好的class文件加载到内存中,并对该数据进行验证、解析和初始化,最终形成JVM可以直接使用的JAVA类型的过程。

 

(1)、加载:加载阶段其实就是JVM通过一个类的全限定名来获取其定义的二进制字节流,并将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构且在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。在该阶段我们开发人员可以干预,例如:我们可以指定类加载器来加载该字节数组或者自定义类加载器来加载。

(2)、链接:将java类的二进制代码合并到JVM的运行状态中的过程

a、验证:验证是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

b、准备:该阶段是在方法区中为类变量(static变量)分配内存并设置类变量初始值。例如:public static int flag=1;该阶段初始化值为0。

c、解析:虚拟机将常量池中的符号引用替换为直接引用的过程。(直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄)

(3)、初始化:初始化为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。

  • 初始化阶段就是执行类构造器<clinit>()的过程,类构造器<clinit>()是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的。

  • 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先初始化其父类。

  • 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。

  • 当访问一个java 类的静态域时,只有正真申明这个域的类才会被初始化。

类的初始化时机:

  • 当虚拟机启动则一定会加载main方法所在的类

    width=100"静态代码块"

  • 当初始化一个类时,如果其父类未被初始化则一定先初始化其父类

   = A "静态代码块A""静态代码块FatherA"

  静态代码块FatherA
静态代码块A

  • new一个对象的时候类被加载

  • 调用类的静态方法和静态成员变量(除了final常量 常量在编译阶段就存入调用类的常量池中,所以无需初始化类)

  • 使用java.lang.reflect包中的方法进行反射调用类会被初始化

类的被动引用不会初始化类:

  • 调用final常量不会初始化应为 常量在编译阶段就存入调用类的常量池中,所以无需初始化类。

  • 通过数组定义的类引用不会初始化类

   = A[10"静态代码块A"

  • 当访问一个静态变量时,只有正真声明这个静态变量的类才会被初始化(通过子类调用父类的静态变量,子类不会被初始化)

    A "静态代码块A"   width=100"静态代码块FatherA"静态代码块FatherA
 

(4)、卸载

Java虚拟机将结束生命周期的时机:

  • 执行了System.exit()方法

  • 程序正常执行结束

  • 程序在执行过程中遇到了异常或错误而异常终止

  • 由于操作系统出现错误而导致Java虚拟机进程终止















本文转自xsster51CTO博客,原文链接: http://blog.51cto.com/12945177/1950756,如需转载请自行联系原作者



相关文章
|
3月前
|
前端开发 安全 Java
聊聊Java虚拟机(一)—— 类加载子系统
虚拟机就是一款用来执行虚拟计算机指令的计算机软件。它相当于一台虚拟计算机。大体上,虚拟机分为系统虚拟机和程序虚拟机。系统虚拟机就相当于一台物理电脑,里面可以安装操作系统;程序虚拟机是为了执行单个计算机程序而设计出来的虚拟机。其中 Java 虚拟机就是**执行 Java 字节码指令的虚拟机**。
45 2
|
7月前
|
前端开发 安全 Java
JVM类加载和双亲委派机制
JVM类加载和双亲委派机制
106 0
|
7天前
|
存储 前端开发 安全
JVM内部世界(内存划分,类加载,垃圾回收)(上)
JVM内部世界(内存划分,类加载,垃圾回收)
39 0
|
2月前
|
安全 Java 程序员
深入理解jvm - 类加载过程
深入理解jvm - 类加载过程
49 0
|
4月前
|
存储 前端开发 安全
浅谈 JVM 类加载过程
浅谈 JVM 类加载过程
42 0
|
4月前
|
存储 安全 Java
JVM类加载(类加载过程、双亲委派模型)
JVM类加载(类加载过程、双亲委派模型)
|
5月前
|
存储 算法 安全
面试~jvm(JVM内存结构、类加载、双亲委派机制、对象分配,了解垃圾回收)
面试~jvm(JVM内存结构、类加载、双亲委派机制、对象分配,了解垃圾回收)
53 0
|
7月前
|
安全 前端开发 Java
JVM概述和类加载子系统
我记得当年学java的时候,就很好奇,为什么我在IDEA上写一些代码(其实就是一堆我们人能知道的英文单词的组合加一些运算符),为什么就可以在windows上运行后执行我们的指令,而且还可以打成jar包去linux系统跑起来,为什么一份代码可以在不同平台运行呢?类是如何加载的?对象如何创建的以及都有哪些信息?我创建的对象被分配到哪个内存去了?java是怎么和我们操作系统打交道的又是怎么调用CPU为我们计算的?创建了对象分配了内存,为什么可以不用手动回收就可以自动清理内存等等等,相信你也同样有过这些困惑。
57 0
|
8月前
|
存储 安全 前端开发
【jvm系列-02】jvm的类加载子系统以及jclasslib的基本使用
【jvm系列-02】jvm的类加载子系统以及jclasslib的基本使用
52 0
|
9月前
|
存储 Java Linux
Java类加载过程、为什么会出现JVM?
也就是说Java程序可以在windows操作系统上运行,不做任何修改,同样的java程序可以在Linux操作系统上运行,跨平台。