Dalvik虚拟机中Java类的加载过程
首先需要明白一点,Java类在使用之前必须先被加载。关于加载其实分为显式加载和隐式加载,显式加载就是我们通过自己来调用相应的加载方法来对特定的类进行加载,隐式加载就是在使用类的时候如果这个类没有被加载过可能就会触发其加载,这个可能是无感知的。下面对类的加载进行一下梳理,主要有以下情形来实现对类的加载。Class.forName()Class.forName()我们在Android...
首先需要明白一点,Java类在使用之前必须先被加载。关于加载其实分为显式加载和隐式加载,显式加载就是我们通过自己来调用相应的加载方法来对特定的类进行加载,隐式加载就是在使用类的时候如果这个类没有被加载过可能就会触发其加载,这个可能是无感知的。
下面对类的加载进行一下梳理,主要有以下情形来实现对类的加载。
Class.forName()
Class.forName()我们在Android开发中经常使用,主要就是用来获取某个类的Class对象,同时完成对该类的加载。下面我们来分析分析它的实现过程。
具体的调用过程如上,其实质就是调用了ClassLoader的loadClass方法来进行类的加载。
env→FindClass()
这个是在jni中执行的,用来在jni层进行java类的查找,并且实现在jni中对java类以及方法的调用和操作。下面我们来看看它的实现原理。
结合上面的Class.forName()的实现过程来看,因为它们它们的实现原理是一样的,最终都是调用了ClassLoader的loadClass方法来进行类的加载。
使用或者实例化某个类
使用或者实例化某个类的时候,就会触发加载。
例如,当我们创建一个对象的时候,如果这个类没有被加载,就会触发其加载,在Java字节码中,通过new-instance指令创建对象,我们可以具体来看看它的执行。
可以看到,它跟前面两个的过程其实是一样的,最终还是调用ClassLoader的loadClass方法来进行类的加载,为什么都会调用这个方法来实现对类的加载呢?其实很好理解,因为我们的dex的加载就是使用ClassLoader完成的,我们在加载某个类的时候首先需要查找到该类,查找的位置肯定是在dex中,所以肯定需要使用ClassLoader来加载,解铃还须系铃人。下面来看看ClassLoader的loadClass方法的调用过程。
具体过程可以看上面的注释,其实这个过程就是dex加载过程的逆过程。首先需要遍历dex列表来查找指定的类,然后将其转换成一个ClassObject对象。具体如下图:
为什么需要进行类的预加载?
有的时候,为了提高程序的运行速度,我们可以选择对需要使用的类提前进行预加载,这样就可以有效的减少类的加载时间。
例如,在Zygote进程中,当我们的虚拟机启动之后,就会调用ZygoteInit类的main方法,进入java运行环境。在ZygoteInit类的main方法中调用preload()方法来进行了一些预加载的操作,我们可以具体看看。
上面就是使用Class.forName对一些需要的类进行了预加载,这样在使用这些类的时候,就可以直接从缓存中获取到对应的ClassObject结构对象,而不需要重新进行加载,其实类的加载过程还是比较耗时的,预加载就可以有效的减少程序运行中不必要的类加载时间,从而提高程序的运行速度。
总结
我们的Dex文件首先是会被ClassLoader进行加载并且解析,所以当我们进行类加载的时候,就会通过ClassLoader来对它已加载的dex进行查找,在dex中找到对应的class定义信息,然后对其进行解析得到一个ClassObject结构体对象。这个ClassObject结构体其实就是我们Java层最终得到的Class对象。
更多推荐
所有评论(0)