JVM 之类加载器
一、什么是 JVM
JVM(Java Virtual Machine)是一个可以执行 Java 字节码文件(即 .class 文件)的虚拟机进程。当 Java 源文件能被成功编译成 .class 文件,就能在不同平台上的不同版本的 JVM 运行,因为 JVM 能将相同的 .class 文件解释称不同平台的机器码。正是因为 JVM 的存在,Java 被称为与平台无关的语言。
一般而言,.java 文件经过编译后会得到 .class 文件,而将这个文件加载到内存之前需要先通过类加载器,先简单过一下图:

二、类加载过程
类加载的过程为: 加载-->连接(验证-->准备-->解析)-->初始化。下面介绍其中的几个过程。
1、加载
这个过程主要是通过类的全限定名,例如 java.lang.String 这样带上包路径的类名,获取到字节码文件;然后将这个字节码文件代表的静态存储结构(可简单理解为对象创建的模板)存在方法区,并在堆中生成一个代表此类的 Class 类型的对象,作为访问方法区中“模板”的入口,往后创建对象的时候就按照这个模板创建。
举个例子,有时候通过反射创建对象,像当初学 JDBC 时会通过 Class.getName("com.mysql.jdbc.Driver.class").newInstance() 创建对象,通过 Class 和相应的全限定类名获取到方法区中的“模板”然后创建对象。

2、验证
验证过程主要确保被加载的类的正确性。首先要先验证文件格式是否规范,如果只是通过 .class 后缀来辨别,那随便把后缀名改一下就可以跑程序了,那岂不是很容易出事。来看看字节码文件大概是长什么样的:

注意看前缀 cafe babe(咖啡宝贝?)这只是验证的其中一个点,还会验证字节码文件里是否包含主次版本号等验证信息。
3、准备
这个阶段主要是给类变量(静态变量)分配方法区的内存并初始化。实例变量不是在这个阶段分配内存,实例变量是随着对象一起分配在堆中。另外,给静态变量初始化为零值或空值,比如public static int n=5;这里并不是马上给 n 这个变量赋值为 5,而是先将其赋值为 0,类似的,如果是引用数据类型,则默认为 null。还有一点需要注意的是,对于 final 类型的数据,必须在程序内给它赋值,系统不会自动初始化,例如 static String str = "hello" + “world”;String 是 final 类型的,在编译阶段就给它优化成 static String str = "helloworld” ,并且将 "helloworld" 放进了常量池。
4、初始化
这个阶段就是将静态变量赋值为初始值,还是 public static int n=5; 这回给 n 赋值为 5 了。
三、类加载器

启动类加载器是由C/C++写的,主要负责加载 jre\lib 目录下的类;扩展类加载器主要负责加载 jre\lib\ext 目录下的类;而应用程序类加载器主要负责加载我们自己编写的类;当然还能自己写类加载器,即自定义加载器。程序主要由前面三个类加载器相互配合加载的。
public class Main {
public static void main(String[] args) {
Main main = new Main();
System.out.println(main.getClass().getClassLoader());
System.out.println(main.getClass().getClassLoader().getParent());
System.out.println(main.getClass().getClassLoader().getParent().getParent());
}
}
由于启动类加载器是 C/C++ 语言写的,所以输出为 null
双亲委派机制
在类加载的过程中,存在着双亲委派机制,即当要加载一个类时,先由父类加载器加载,当父类加载器没办法加载时,才由下面的加载器加载,来看一个程序:
package java.lang; // 自定义的包
public class String {
public static void main(String[] args) {
System.out.println("这是自定义的java.lang.String类");
}
}

由于 jre\lib\ext 中存在 java.lang.String 类,当加载该类的时候,根据全限定名进行查找,找到后由启动类加载器加载,发现 String 类中不包含 main() 方法,因此程序出错。
JVM 之类加载器的更多相关文章
- JVM自定义类加载器加载指定classPath下的所有class及jar
一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...
- 【深入理解JVM】类加载器与双亲委派模型 (转)
出处: [深入理解JVM]类加载器与双亲委派模型 加载类的开放性 类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因.在类加载的第一阶段“加载”过程中,需要通过 ...
- 1.1 jvm核心类加载器--jdk源码剖析
目录 前提: 运行环境 1. 类加载的过程 1.1 类加载器初始化的过程 1.2 类加载的过程 1.3 类的懒加载 2. jvm核心类加载器 3. 双亲委派机制 4. 自定义类加载器 5. tomca ...
- 【JVM】JVM之类加载器
一.前言 首先,小小测试,看是否已经掌握了JVM类加载的过程 1.1.测试一 class Singleton { private static Singleton sin = new Singleto ...
- JVM之类加载器下篇
除了自定义的类加载之外,jvm存在三种类加载器,并以一种父委托的加载机制进行加载. --启动类加载器,又称根加载器,是一个native的方法,使用c++实现.在java中我们用null标识,用于加载j ...
- 【深入理解JVM】类加载器与双亲委派模型
原文链接:http://blog.csdn.net/u011080472/article/details/51332866,http://www.cnblogs.com/lanxuezaipiao/p ...
- JVM学习一:JVM之类加载器概况
18年转眼就3月份都快结束了,也就是说一个季度就结束了:而我也因为年前笔记本坏了,今天刚修好了,那么也应该继续学习和博客之旅了.今年的博客之旅,从JVM开始学起,下面我们就言归正传,进入正题. 一.J ...
- (转)JVM——自定义类加载器
背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上 ...
- JVM虚拟机-类加载器子系统
转自博客:http://www.cnblogs.com/muffe/p/3541189.html 还有一些自己补充的知识点 一.类加载器基本概念 顾名思义,类加载器(class loader)用来 ...
- 深入理解JVM一类加载器原理
我们知道我们编写的java代码,会经过编译器编译成字节码文件(class文件),再把字节码文件装载到JVM中,映射到各个内存区域中,我们的程序就可以在内存中运行了.那么字节码文件是怎样装载到JVM中的 ...
随机推荐
- Linux如何永久打开端口
由于防火墙导致同局域网无法通过IP访问,Linux有多种防火墙,需要查看当前使用的防火墙(开机自启),再进行配置 以下是 iptables 和 firewall 防火墙的相关配置,切忌将自己配置的防 ...
- 【转】diamond专题(四)—— 容灾机制
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...
- springboot2.x 整合redis集群的几种方式
一.不指定redis连接池 #系统默认连接池 yml配置文件: spring: redis: cluster: nodes: - 192.168.1.236:7001 - 192.168.1.236: ...
- JVM系列1:内存区域
1.JVM运行区域内存划分 2.各内存区域详细介绍 2.1 程序计数器 程序计数器是一块很小的内存区域,它作为前线程所执行的字节码的行号指示器,指向当前class文件的执行代码的行数.字节码解释器工作 ...
- nodejs之静态文件托管、 路 由、EJS 模板引擎、GET、POST
1.静态文件托管 静态文件托管:是指对于一个js方法进行封装,提高代码可读性 //fs模块 var fs=require('fs'); //path模块 var path=require('path' ...
- Docker环境安装部署Java应用(含安装Tomcat和JDK)
1.部署思路 两台docker机(centos 7系统),Docker 版本:18.09.6, build 481bc77156 Docker host IP:192.168.102.135 Dock ...
- 无界面上(linux)生成测试报告(3)
无界面上(linux)生成测试报告 1.待jmx文件运行完成后,键入命令进入到jtl文件下: #cd testresult#bin目录下使用此命令,进入到jtl文件下 #jmeter -g pushG ...
- PS 之图片中抠出大树
工具:Photoshop CC2017 原图:(目的是将大树从图片中抠出) 操作: 1.打开要抠图的图片,然后执行:[图层]---->[新建调整图层]---->[反相]---->[在 ...
- Git 提交 .gitignore文件
问题描述 不知道小伙伴有木有遇到这种情况:想在工程里增加 .gitignore 文件,用于在以后提交后,过滤哪些文件或者目录. 但是,在当前工程的根目录下,执行如下执行命令后,依然不能把 .gitig ...
- 分布式任务celery
Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成. 消息中间件 Celery本身不提 ...