JVM之类加载器
2016-06-06 11:11
435 查看
JVM之类加载器
1.类加载器:通过一个类的全限定名称来获取描述此类的二进制字节流的过程,该动作在虚拟机的外部实现,目的是方便应用程序自己决定如何获取所需要的类,从Java虚拟机的角度只存在两种不同的类加载器:启动类加载器(C++语言实现),其它(Java语言实现,独立于虚拟机外部继承自抽象类java.lang.ClassLoader)。从开发人员角度,大部分Java程序会用到以下三种类加载器:.启动类加载器,主要负责<JAVA_HOME>\bin目录下类的加载;
.扩展类加载器,负责加载<JAVA_HOME>\lib\etc 目录下类的加载;
.应用程序类加载器,负责加载用户类路径(ClassPath)上所指定的类库,一般为程序中默认的类加载器;
2.类的唯一性:任意一个Java类都需要由加载它的类加载器以及该类本身共同确定该类在JVM虚拟机中的唯一性,比较两个类是否相等的前提是由同一个类加载器的前提下。常见的equals(),isAssignableFrom(),isInstance(),instanceOf关键字等。可使用如下代码进行验证:
/*自定义类加载器*/
public class XClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
String fileName = name.substring(name.lastIndexOf('.') + 1) + ".class";
/* 将Class字节流转为输入流 */
InputStream is = getClass().getResourceAsStream(fileName);
if (is == null) {
return super.loadClass(name);
}
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name, b, 0, b.length);
} catch (IOException e) {
e.printStackTrace();
}
return super.loadClass(name);
}
/* 验证类的唯一性条件 */
public static void main(String[] args)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
XClassLoader classLoader = new XClassLoader();
Object obj = classLoader.loadClass("cn.com.xiaofen.Hello").newInstance();
System.out.println(obj.getClass());
System.out.println(obj instanceof cn.com.xiaofen.Hello);
}
}
3.双亲委派模型:为保证在JVM中同一个.class文件被不同的类加载器加载都是同一个Class对象。示意图如下:
.双亲委派模型要求除了顶层启动类加载器之外,其余的类加载器都应当有自己的父类加载器,此处的父子关系通常使用组合的关系来复用父加载器的代码。
.双亲委派模型并不是一个强制性的约束模型,而是Java设计者推荐给开发者的一种类加载器实现方式。
.工作流程,如果一个类加载器收到类加载请求,首先将请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的类加载请求都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成类加载请求时,子类才会尝试自己去加载。
.双亲委派模型对于Java应用程序的稳定运作很重要,实现方式却很简单
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// 检查该类是否已经被加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
/* 委托父类加载器 */
c = parent.loadClass(name, false);
} else {
/* 当前类加载器加载 */
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
/* 任然没有发现调用本类的findClass 方法加载 */
long t1 = System.nanoTime();
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;
}
}
4.破坏双亲委派模型
.第一次被破坏,重写java.lang.ClassLoader的protected 方法loadClass()。
.第二次被破坏,发生在基础类(越基础的类越有顶层类加载器加载)调用回用户代码的场景中,启动类无法加载用户代码。Java中使用线程上下文类加载器进行设置,该加载器通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果线程创建时候没有设置,将从父线程中继承一个,如果在应用程序范围内都没有设置过,则默认使用应用程序类加载器。会出现父类加载器调用子类加载器完成类加载的情况。
.第三次被破坏,用户对程序的动态性追求而导致,常见的:代码热替换、模块热部署等等。OSGI(Java动态化模块化系统的一系列规范)环境下,类加载器不再是双亲委派模型中的树状结构,而是更加负责的网状结构。
参考《深入理解Java虚拟机第二版》
相关文章推荐
- Java 6 JVM参数选项大全(中文版)
- 深入解析JVM对dll文件和对类的装载过程
- JVM Tomcat性能实战(推荐)
- Java虚拟机JVM性能优化(二):编译器
- Java程序员必须知道的5个JVM命令行标志
- Java虚拟机JVM性能优化(三):垃圾收集详解
- 简单谈谈JVM、JRE和JDK的区别与联系
- 解析Java虚拟机中类的初始化及加载器的父委托机制
- JAVA中JVM的重排序详细介绍
- 浅谈Java的虚拟机结构以及虚拟机内存的优化
- JVM角度调试优化MyEclipse
- Java虚拟机JVM性能优化(一):JVM知识总结
- Android Studio 报错failed to create jvm error code -4的解决方法
- 解析Linux系统中JVM内存2GB上限的详解
- 了解Java虚拟机JVM的基本结构及JVM的内存溢出方式
- Java堆空间占满的gc日志实例
- JVM调优之Tomcat启动参数配置及详解(一)
- java动态代理模式
- Groovy Meta Object Protocol
- java类文件结构