Java类加载和对象创建
引言
Java代码需要被使用,必须要经过类加载器加载到内存中,然后对应的类才能够被创建使用,这文对类加载和对象创建和过程进行分析。
类加载
Java类通过懒加载的方式,经过了Loading、Linking、Initializing后加载到内存中,才能被进行使用。

Loading
懒加载
Java类并不是JVM虚拟机启动的时候,就对所有用到的类进行全部加载,而是在第一次使用到的时候,进行加载
LazyLoading五种情况
- new getstatic putstatic invokestatic指令,访问final变量除外
- java.lang.reflect对类进行反射调用时
- 初始化子类的时候,父类首先初始化
- 虚拟机启动时,被执行的主类必须初始化
- 动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstatic REF_putstatic REF_invokestatic的方法句柄时,该类必须初始化
双亲委派
Java类加载的时候,默认情况下,遵循双亲委派的原则(自下向上的查找,自顶向下的加载),为了类安全,核心类不会遭到破坏

ClassLoader源码
ClassLoader三个步骤
findInCache -> parent.loadClass -> findClass()
在抽象类ClassLoader里面,通过模板方法的方式,给出了默认未重写情况下的LoadClass方法
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
//先在自己的缓存中查找是否已经加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
//如果自己没有加载过,就交给父类去加载
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//Bootstrap加载器的parent变量为空,当发现parent为空时,则使用bootstrap自己去加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
//当交给父类加载器去加载后,如果没有加载到返回了NULL,则自己去进行加载
//这个地方会报ClassNotFound异常,但如果还有子加载器的话,则会在上面被捕捉到,如果已经是最子级加载器的话,则直接报异常。
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
//进行解析
resolveClass(c);
}
//返回调用的地方
return c;
}
}
一般情况下,不需要打破双亲委派的,在自定义ClassLoader的时候,只需要重写findClass方法即可。
自定义ClassLoader
- 继承ClassLoader
- 重写findClass方法
将字节码文件读入到内存,将其转换成Byte数据,通过defineClass将其转换成对应的Class对象。
FileInputStream -- read进内存 -> 写进ByteArrayOutputStream,再转换成Byte数组
默认的情况下,自定义ClassLoader的parent字段是AppClassLoader,如果没有重写LoadClass方法,则依然遵循双亲委派的加载原则。
思考:如何打破双亲委派原则
通过重写loadClass方法即可打破双亲委派的原则
思考:什么情况下需要打破双亲委派
- JDK1.2之前,自定义ClassLoader都必须重写loadClass()
- ThreadContextClassLoader可以实现基础类调用实现类代码,通过thread.setContextClassLoader指定、
- 热启动,热部署,tomcat有自己的模块指定classloader(可以加载同一类库的不同版本),还可以实现不同Web Context进行类隔离
Linking
Linking的时候,实际是有三个步骤
Verification(校验)
验证文件是否符合JVM规定
Preparation(准备)
将类的静态变量赋默认值
Resolution(解析)
将类、方法、属性等符号引用解析为直接引用
常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用
Initializing
对类进行初始化,调用类初始化代码 clinit,给静态成员变量赋初始值,按顺序执行
对象创建
申请对象内存

图中可以看到,优先在栈上分配->TLAB->老年代->Eden区
栈上分配:对象生命周期随着方法的调用开始而开始,结束而结束,不需要进行垃圾回收减轻了GC的负担
TLAB: 线程私有的堆内存,可以很好的避免了共享堆中多个线程操作堆内存分配对象空间时产生的同步问题(虽然有CAS+失败重试),从而提高堆上对象分配的效率。成员变量赋默认值
调用构造方法init(成员变量赋初始值,调用类的相应的构造方法)

JVM执行模式
解释模式
- 通过解释器(Bytecode Interpreter)解释执行
- 特点:启动快(不需要编译),执行慢
- 可通过-Xint参数指定为纯解释模式
编译模式
- 由JIT(Just In-Time Compiler)编译为本地代码(C语言实现)执行
- 特点:启动慢(编译过程较慢),执行快
- 可通过-Xcomp参数指定为纯编译模式
混合模式
- 混合使用解释器 + 热点代码编译
- 起始阶段采用解释执行
- 热点代码检测(HotSpot),默认-XX:CompileThreshold=10000
- 多次被调用的方法(方法计数器:监测方法执行频率)
- 多次被调用的循环(循环计数器:监测循环执行频率)
- 对热点代码进行编译
- 默认采用这种模式,可通过-Xmixed指定
Java类加载和对象创建的更多相关文章
- java类加载、对象创建过程
类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在.如果有,就直接使用:如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加 ...
- java基础---类加载和对象创建过程
类中可以存在的成员: class A{ 静态成员变量: 非静态成员变量: 静态函数: 非静态函数: 构造函数 A(..){...} 静态代码块 static{...} 构造代码块 {...} } 类加 ...
- Java 虚拟机的对象创建
堆中存储的内容:在程序运行时,动态创建的对象. 创建对象的四种方式:new,clone(浅复制),反射,反序列化. 浅复制:只能复制当前对象本身,如果当前对象(A)引用了另外的对象(B),则引用对象( ...
- Java虚拟机(二)-对象创建
这一篇大致说明一下,对象在Java堆中对象分配.内存布局以及访问定位 1.对象的创建 虚拟机在遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引 ...
- java类加载和对象初始化
对象初始化过程: 1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 3.其次,初 ...
- Java中String对象创建机制详解()
一String 使用 private final char value来实现字符串存储 二Java中String的创建方法四种 三在深入了解String创建机制之前要先了解一个重要概念常量池Const ...
- JAVA类和对象创建
面向对象 学习目标: 理解面向对象的编程思想 理解类与对象的关系 如何创建类与对象 方法重载 一:什么是面向对象编程(OOP) 面向对象编程(Object Oriented Programming,O ...
- Java中类加载过程和对象创建过程
类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在.如果有,就直接使用:如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加 ...
- Java中对象创建过程
本文介绍的对象创建过程仅限于普通Java对象,不包括数组和Class对象. 1.类加载检查 虚拟机遇到一条new指令时,首先去检查该指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号引用 ...
- 【Java基础】Java类的加载和对象创建流程的详细分析
相信我们在面试Java的时候总会有一些公司要做笔试题目的,而Java类的加载和对象创建流程的知识点也是常见的题目之一.接下来通过实例详细的分析一下. 实例问题 实例代码 Parent类 package ...
随机推荐
- Flagger on ASM·基于Mixerless Telemetry实现渐进式灰度发布系列 1 遥测数据
简介: 服务网格ASM的Mixerless Telemetry技术,为业务容器提供了无侵入式的遥测数据.遥测数据一方面作为监控指标被ARMPS/prometheus采集,用于服务网格可观测性:另一方面 ...
- Java编程技巧之单元测试用例编写流程
简介: 立足于"如何来编写单元测试用例",让大家"有章可循",快速编写出单元测试用例. 作者 | 常意来源 | 阿里技术公众号 温馨提示:本文较长,同学们可收藏 ...
- Cloudera CDP 企业数据云测试开通指导
简介:基于阿里云部署的 Cloudera CDP 企业数据云平台已经进入公测阶段,本文详细介绍了相关试用/试用流程. 基于阿里云部署的 Cloudera CDP 企业数据云平台已经进入公测阶段,如对 ...
- [Gin] 运行模式检测和设置 (mode.go)
// 设置方式 gin.SetMode(gin.ReleaseMode) // 检测方式 if gin.Mode() == gin.DebugMode { } 更多相关信息,建议直接去看源代码. Re ...
- RT-Thread线程同步与线程通信
一.线程同步 线程同步的使用场景 例如一项工作中的两个线程:一个线程从传感器中接收数据并且将数据写到共享内存中,同时另一个线程周期性的从共享内存中读取数据并发送去显示,下图描述了两个线程间的数据传递: ...
- 一个支持Sora模型文本生成视频的Web客户端
大家好,我是 Java陈序员. 最近 Open AI 又火了一把,其新推出的文本生成视频模型 -- Sora,引起了巨大的关注. Sora 目前仅仅只是发布预告视频,还未开放出具体的 API. 今天, ...
- R1_ES知识图谱
业务量增加,优化..优化... 学习... 学习..... 阮一鸣,eBay Pronto 平台技术负责人,管理了 eBay 内部上百个 Elasticsearch 集群,数据规模超过 4000 节点 ...
- 如何阅读 Paper
前言 论文(Paper)通常是新技术.算法.编程方法或软件工具的首次公布.通过阅读论文,我们可以了解最新的技术进展,保持自己的技能和知识是最新的. 同时,论文提供了对特定主题深入理解的机会.它们通常包 ...
- idea在商店无法搜索到插件
背景:我使用的版本是IDEA ultimate 2019.2 版本印象中,最初安装的时候,商店还是可以用的,突然有一天,就无法使用了.下边直入正题: 解决办法:1.首先浏览器登陆下:https://p ...
- golang复用http.request.body
golang复用http.request.body 问题及场景 业务当中有需要分发http.request.body的场景.比如微信回调消息只能指定一个地址,所以期望可以复制一份消息发给其他服务.由服 ...