深入理解JVM之类加载
---
title: 【学习】深入理解JVM之类加载.md
date: 2019-10-20 22:20:06
tags: JVM 类加载
---
Java类的加载,连接,初始化都是在程序运行期间执行的
## Java 虚拟机与程序的生命周期
1. 执行 System.exit()方法
2. 程序正常结束
3. 遇到异常或错误终止
4. 由于操作系统或程序虚拟机进程错误
以上的情况都可以结束生命周期
## Java 类加载的方式
1. 本地系统直接加载
2. 通过网络下载.class 文件
3. 通过zip,jar 等归档文件加载
4. 从专有数据库中加载.class 文件
5. 通过java 文件动态编译源文件得到.class 文件
## 类加载器有哪些
- 系统自带的类加载器
- 根类加载器(Bootstrap ClassLoader)
- 扩展类加载器(Extension ClassLoader)
- 系统类加载器(System ClassLoader)
- 用户自定义类加载器
- 通过ClassLoader来实现自定义的类加载器
使用java.lang.ClassLoader的子类,通过ClassLoader来实现自定义的类加载器,这个过程中可以定义类的**加载方式**,**加载时机**以及加载过程中做一些事情。
## 类加载过程
**类的加载指的是将类的.class 文件中的二进制数据读入到内存中.将其放在运行时数据区的方法区内,然后在内存中创建一个 java.lang.Class 对象(虚拟机规范并未说明Class对象在哪里,HotSpot 虚拟机将其放在方法区)用来封装类在方法区内的数据结构**
- 加载
查找并加载类的二进制数据
- 连接
- 验证
确保被加载的类的**正确性**
- 准备
为类的**静态变量**分配内存, 并将其初始化为**默认值**
- 解析
把类中的**符号引用换做**是**直接引用**
- 初始化
为类的静态变量赋予**正确的值**
## Java 程序对类的使用方式
所有的 java 虚拟机实现必须在每个类或接口被 Java 程序**首次主动使用**才初始化
-XX:+TraceClassLoading 可以查看类加载
- 主动使用会初始化(7 个)
1. 创建类实例
2. 访问某个类或接口的静态变量,或者对该类的静态变量赋值
3. 调用类的静态方法
4. 反射(Class.forName("com.test.Test"))
5. 初始化一个类的子类
6. java 虚拟机启动时,被表明为启动类的类
7. JDK1.7提供的实例解析结果REF_getStatic,REF_putStatic,REF_invokeStatic句柄对应的类没有初始化则初始化
- 被动使用初始化
> 对于静态字段来说,只有**直接定义了该字段的类**才会被初始化
~~~java
public class Mytest1 {
public static void main(String[] args) {
System.out.println(Mychirld1.str);
}
}
/**
* 对于静态字段来说,只有直接定义了该字段的类才会被初始化
*/
class Myparent1 {
public static String str = "hello world !";
static {
System.out.println("current in Myparent1");
}
}
class Mychirld1 extends Myparent1{
public static String str2 = "hello world2 !";
static {
System.out.println("current in Mychirld1");
}
}
>>>>>>
current in Myparent1
hello world !
~~~
main 方法里使用子类去调用了父类的静态变量 因只有直接定义了该字段的类才会被初始化,所以先初始化打印父类的静态代码块内容,且子类不初始化
> 当一个类初始化的时候,要求其父类全部初始化完毕
这个是主动使用,就会初始化
~~~java
public class Mytest1 {
public static void main(String[] args) {
System.out.println(Mychirld1.str2);
}
}
/**
* 对于静态字段来说,只有直接定义了该字段的类才会被初始化
*/
class Myparent1 {
public static String str = "hello world !";
static {
System.out.println("current in Myparent1");
}
}
class Mychirld1 extends Myparent1{
public static String str2 = "hello world2 !";
static {
System.out.println("current in Mychirld1");
}
}
>>>>>>
current in Myparent1
current in Mychirld1
hello world2 !
~~~
main 方法中调用了子类的静态变量,主动初始化子类,根据类的加载顺序会先初始化父类,所以先打印父类的静态代码块中的东西,在打印子类的.
> 被 final 修饰的变量
当一个main 方法引用了一个类的被 final 修饰的静态变量会主动触发其初始化么?
~~~java
public class Mytest2 {
public static void main(String[] args) {
System.out.println(Myparent2.str);
}
}
class Myparent2 {
public static final String str = "hello world !";
static {
System.out.println("current in Myparent1");
}
}
>>>>>
hello world !
~~~
答案是不会的,
因为被 final 修饰作为一个常量,会在编译阶段,就会被放置在调用该常量的方法所在的类的常量池中.本质上,调用该常量的类和常量定义的类已经没有直接引用的关系了,我们将编译时期Myparent2.class 删除,运行 main 方法也会打印hello world !
>创建数组实例
~~~java
public class Mytest3 {
public static void main(String[] args) {
Myparent3[] myparent3s = new Myparent3[1];
}
}
class Myparent3 {
static {
System.out.println("current in parent3");
}
}
~~~
这种情况什么输出都没有.因为对于数组实例来说,其类型是由 JVM 在运行期动态生成
> 接口初始化
接口中的字段默认都是public static final
***当一个接口初始化时,并不要求其父接口都完成了初始化只有在真正使用到父接口的时候(如引用到接口中所定义的常量时),才会初始化(但子接口初始化,父接口一定会被加载)***
~~~java
public class Mytest5 {
public static void main(String[] args) {
System.out.println(Mychirld5.b);
}
}
interface Myparent5 {
public static final int a = 7;
}
interface Mychirld5 extends Myparent5 {
public static final int b = new Random().nextInt(2);
}
>>>>
可通过 -XX:+TraceClassLoading查看父接口是否被初始化
~~~
> 助记符
```
/**
* 助记符
*
* idc 表示将 int,float 或是 String 类型的常量值从常量池中推送至栈顶
* bipush 表示将单字节(-128~127)的常量值推送至栈顶
* sipush 表示将一个短整型常量值(-32768~32767)推送至栈顶
* iconst_1 表示将 int 类型 1 推送至栈顶(iconst_1 - iconst_5)
*/
```
## 总结
类加载的整个过程
开始 ---> 有类加载器加载类 ---> 连接 ----> 初始化 ---> 使用类 ---> 卸载
|---->验证
| ----> 准备
| ----> 解析
> 加载
就是把二进制类型的 java 类型读入 java 虚拟机红
> 连接
验证:
确保被加载的类的**正确性
准备:
1.为变量分配内存,设置默认值 2.在未达到初始化,类变量都没有初始化为真正的初始值
解析:
在类型的常量池中,寻找类,接口,字段和方法的符号引用,把这些引用替换为直接引用的过程
> 初始化
为 变量赋初始值
> 类实例化
1.为新的对象分配内存 2.为实例变量赋默认值3.为实例变量赋正确的初始值
深入理解JVM之类加载的更多相关文章
- 【深入理解JVM】类加载器与双亲委派模型 (转)
出处: [深入理解JVM]类加载器与双亲委派模型 加载类的开放性 类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因.在类加载的第一阶段“加载”过程中,需要通过 ...
- 深入理解JVM的类加载
前言: 前面又说到Java程序实际上是将.class文件放入JVM中运行.虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换,解析和初始化,最终形成可以被虚拟机直接使用的Java类 ...
- 【深入理解JVM】类加载器与双亲委派模型
原文链接:http://blog.csdn.net/u011080472/article/details/51332866,http://www.cnblogs.com/lanxuezaipiao/p ...
- 深入理解JVM(3)——类加载机制
1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...
- 深入理解JVM一类加载器原理
我们知道我们编写的java代码,会经过编译器编译成字节码文件(class文件),再把字节码文件装载到JVM中,映射到各个内存区域中,我们的程序就可以在内存中运行了.那么字节码文件是怎样装载到JVM中的 ...
- 深入理解JVM - 虚拟机类加载机制 - 第七章
类加载的时机类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括了:加载/验证/准备/解析/初始化/使用/卸载七个阶段.其中验证/准备和解析统称为连接(Linking). 加载.验证.准 ...
- 深入理解JVM,类加载器
虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流(即字节码)”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称 ...
- 理解JVM之类加载机制
类完整的生命周期包括加载,验证,准备,解析,初始化,使用,卸载,七个阶段.其中验证,准备,解析统称为连接,类的卸载在前面的关于垃圾回收的博文中已经介绍. 加载,验证,准备,初始化,卸载这五个阶段的顺序 ...
- Java工程师学习指南第6部分:深入理解JVM虚拟机
本文整理了微信公众号[Java技术江湖]发表和转载过的JVM虚拟机相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧吧. JVM原理分析,看了都说好 JVM 深入学习:Java 解析 Cl ...
随机推荐
- Oracle SQL外连接
SQL提供了多种类型的连接方式,它们之间的区别在于:从相互交叠的不同数据集合中选择用于连接的行时所采用的方法不同.连接类型 定义内连接 只连接匹配的行左外连接 ...
- Django ORM 之F、Q查询与事务
返回ORM目录 Django ORM 内容目录 一.F.Q查询 二.事务 三.only与defer 一.F.Q查询 """ Product表中的数据: 1 橡皮 2 20 ...
- Apache虚拟目录实现同一个IP绑定多个域名
在前:我使用的是Xampp,所以路径可能不同 找到apache\conf\extra\httpd-vhosts.conf, 如果没有的话请自己新建httpd-vhosts.conf文件, 并且在htt ...
- Unity 手机屏幕适配
////如有侵权 请联系我进行删除 email:YZFHKM@163.com 1.游戏屏幕适配 屏幕适配是为了让我们的项目能够跑在各种电子设备上(手机,平板,电脑) 那么了解是适配之前首先要了解两个知 ...
- from urllib import parse模块的使用
一.介绍 定义了url的标准接口,实现url的各种抽取 parse模块的作用:url的解析,合并,编码,解码 二.代码 方法一:urlparse 实现url的识别和分段 from urllib imp ...
- Redis-GEO
一. Redis的GEO特性 Redis3.2版本提供了GEO功能,支持存储地理位置信息用来实现诸如摇一摇,附近位置这类依赖于地理位置信息的功能.二. 命令2.1 增加地理位置信息 命令:geoadd ...
- .NETFramework:Exception
ylbtech-System.Exception.cs 1.返回顶部 1. #region 程序集 mscorlib, Version=4.0.0.0, Culture=neutral, Public ...
- (1)python tkinter-窗体
1.导入自带的包名 import tkinter 2.创建一个窗体对象 form=Tkinter.Tk() 3.显示窗体(这句应该是所有的设置部署完最后执行的一句代码) form.mainloop() ...
- maven项目依赖其他jar包的时候,idea运行没问题,java -jar 报错:java.lang.SecurityException: Invalid signature file digest
当项目依赖其他jar包的时候,打出的jar包执行出错,抛出这个异常. 原因:因为依赖jar包中的META-INF中有多余的.SF文件与当前jar包冲突, 解决方案 一 在打包前删除依赖jar包的.SF ...
- netty 解决粘包拆包问题
netty server TimeServer package com.zhaowb.netty.ch4_3; import io.netty.bootstrap.ServerBootstrap; i ...