什么是类加载机制?
Java虚拟机将编译后的.class文件加载到内存中,进行校验、转换、解析和初始化,到最终的使用,这就是类的加载机制。类的加载时机并未有明确的规定,但是类明确了类的初始化时机。
类的加载机制大致分为五个过程:加载、验证、准备、解析、初始化。
通过ClassLoader加载一个Class对象到内存中。具体过程:
验证加载后的类是否符合.Class文件结构,类数据是否符合虚拟机的要求,确保不会危害虚拟机的安全。具体过程如下:
将类符号引用转换成直接引用。
给类变量(static)赋值,并执行static{}方法。这里的触发执行的方法是类构造器中。
类初始化的时机:
这里的ClassLoader是安卓的类加载器,不是Java的加载器,这是有区分的,比如Java的类加载器加载的是jar里面的.class文件的集合,而安卓则是将.class文件的集合全部写入到一个dex文件中,删除一些重复的代码,以此来提高性能。
Android的类加载器类型也可以分为两种:
无论哪种加载器,它们都要继承ClassLoader这个抽象父类。其中系统类加载器主要有:BootClassLoader、PathClassLoader、DexClassLoader
(1) BootClassLoader
class BootClassLoader extends ClassLoader { private static BootClassLoader instance; @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") public static synchronized BootClassLoader getInstance() { if (instance == null) { instance = new BootClassLoader(); } return instance; } ...}
BootClassLoader继承于ClassLoader,它是一个没有父加载器的加载器,它在Zygote进程启动的时候,BootClassLoader加载器将会被创建,用它加载一些预加载类,方便以后fork进程时复用资源。同时它也是ClassLoader的内部类。
(2) PathClassLoader
public class PathClassLoader extends BaseDexClassLoader { /** * @param dexPath : Dex相关文件的路径 * @param parent : 父加载器 */ public PathClassLoader(String dexPath, ClassLoader parent) { super(dexPath, null, null, parent); } /** * @param dexPath: Dex相关文件的路径 * @param librarySearchPath:包含C/C++库的路径集合 * @param parent : 父加载器 */ public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) { super(dexPath, null, librarySearchPath, parent); } ...}
PathClassLoader继承BseDexClassLoader,同时BaseDexClassLoader继承ClassLoader。 PathClassLoader的创建在system_server进程中,PathClassLoader类加载器通常加载已经安装的apk的dex文件。 PathClassLoader类加载器默认的解压的dex文件的存储路径是:/data/dalvik_cache路径中。 如下是创建的时机:
public class ZygoteInit { // 创建完system_server进程后,会执行此方法 private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) { if (systemServerClasspath != null) { //... } else { ClassLoader cl = null; // 创建PathClassLoader加载器 if (systemServerClasspath != null) { cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion); } } } static ClassLoader createPathClassLoader(String classPath, int targetSdkVersion) { String libraryPath = System.getProperty("java.library.path"); // 父加载器是BootClassLoader ClassLoader parent = ClassLoader.getSystemClassLoader().getParent(); // 创建工厂模式创建PathClassLoader return ClassLoaderFactory.createClassLoader(classPath, libraryPath, libraryPath, parent, targetSdkVersion, true /* isNamespaceShared */, null /* classLoaderName */); }}public abstract class ClassLoader { public static ClassLoader getSystemClassLoader() { return SystemClassLoader.loader; } static private class SystemClassLoader { public static ClassLoader loader = ClassLoader.createSystemClassLoader(); } private static ClassLoader createSystemClassLoader() { String classPath = System.getProperty("java.class.path", "."); String librarySearchPath = System.getProperty("java.library.path", ""); // 父加载器是BootClassLoader return new PathClassLoader(classPath, librarySearchPath, BootClassLoader.getInstance()); }}
可见PathClassLoader的父加载器是BootClassLoader。
(3) DexClassLoader
public class DexClassLoader extends BaseDexClassLoader { /** * * @param dexPath : Dex相关文件的路径 * @param optimizedDirectory: 解压的dex的存储路径 * @param librarySearchPath:包含C/C++库的路径集合 * @param parent : 父加载器 */ public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) { super(dexPath, null, librarySearchPath, parent); }}
DexClassLoader也是继承BaseDexClassLoader,相比PathClassLoader则是可以定义解压dex的存储路径。
除了BootClassLoader、PathClassLoader、DexClassLoader这三个类加载器外还有,InMemoryDexClassLoader:用于加载内存的dex;SecureClassLoader:权限检查的ClassLoader;URLClassLoader:URL的ClassLoade。
Android中所有的类加载器都继承于ClassLoader抽象类,这个类的loadClass()方法同样实现了双亲委托机制。
(1) 双亲委托机制
public abstract class ClassLoader { /** * 双亲委托机制 */ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 1. 先检查class是否已经加载过 Class<?> c = findLoadedClass(name); if (c == null) { // 没有加载过 try { if (parent != null) { // 先给父ClassLoader加载Class c = parent.loadClass(name, false); } else { // 调用BootClassLoader加载Class c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // 父的ClassLoader都没有加载class,则调用findClass()给此ClassLoader加载 c = findClass(name); } } return c; } protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }}
ClassLoader的loadClass()方法定义了加载器加载类的过程:
那这个findClass()方法在ClassLoader中是一个空实现,它让给你子类去实现这个查找的过程。那这里以BaseDexClassLoader为例,看findClass()是如何查找class文件的:
public class BaseDexClassLoader extends ClassLoader { private final DexPathList pathList; public BaseDexClassLoader(String dexPath, String librarySearchPath, ClassLoader parent, ClassLoader[] sharedLibraryLoaders, boolean isTrusted) { super(parent); this.sharedLibraryLoaders = sharedLibraryLoaders == null ? null : Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length); this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted); reportClassLoaderChain(); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 调用DexPathList.findClass方法查找class Class c = pathList.findClass(name, suppressedExceptions); if (c == null) { ClassNotFoundException cnfe = new ClassNotFoundException( "Didn't find class /"" + name + "/" on path: " + pathList); for (Throwable t : suppressedExceptions) { cnfe.addSuppressed(t); } throw cnfe; } return c; }}
调用DexPathList.findClass()方法去查找class文件:
public final class DexPathList { private Element[] dexElements; DexPathList(ClassLoader definingContext, String dexPath, String librarySearchPath, File optimizedDirectory, boolean isTrusted) { this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions, definingContext, isTrusted); } public Class<?> findClass(String name, List<Throwable> suppressed) { // 遍历Element数组去查询 for (Element element : dexElements) { Class<?> clazz = element.findClass(name, definingContext, suppressed); if (clazz != null) { return clazz; } } if (dexElementsSuppressedExceptions != null) { suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); } return null; }} /*package*/ static class Element { @UnsupportedAppUsage private final File path; private final Boolean pathIsDirectory; @UnsupportedAppUsage private final DexFile dexFile; private ClassPathURLStreamHandler urlHandler; private boolean initialized; @UnsupportedAppUsage public Element(DexFile dexFile, File dexZipPath) { if (dexFile == null && dexZipPath == null) { throw new NullPointerException("Either dexFile or path must be non-null"); } this.dexFile = dexFile; this.path = dexZipPath; this.pathIsDirectory = (path == null) ? null : path.isDirectory(); } public Class<?> findClass(String name, ClassLoader definingContext, List<Throwable> suppressed) { // 调用DexFile.loadClassBinaryName()方法去查找 return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed) : null; }}public final class DexFile { public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) { return defineClass(name, loader, mCookie, this, suppressed); } private static Class defineClass(String name, ClassLoader loader, Object cookie, DexFile dexFile, List<Throwable> suppressed) { Class result = null; try { result = defineClassNative(name, loader, cookie, dexFile); } ... return result; } private static native Class defineClassNative(String name, ClassLoader loader, Object cookie, DexFile dexFile) }
DexPathList有一个Element[]数组,每个Element有dex文件路径,通过遍历Element[]数组,调用Element. loadClassBinaryName()方法去查找是否对应的class文件,最后调用defineClassNative()native方法去查找。
本文链接:http://www.28at.com/showinfo-26-16132-0.htmlJVM类加载机制分析
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 编写高质量代码的十条黄金法则