深入理解jre,classload,类加载过程

来源:互联网 发布:爱普生手机打印软件 编辑:程序博客网 时间:2024/06/06 00:04

1.JRE目录:

java runtime environment顾名思义,就是java运行环境。

解释参见http://blog.csdn.net/liufeng_cp/article/details/2674317

这就是JRE的目录核心就是两个:

JVM:java虚拟机   (我个人的理解就是bin目录)

lib:基本类库,提供java编程最基本的API   (lib目录)


http://docs.oracle.com/javase/6/docs/technotes/tools/windows/jdkfiles.html

简单一下:

JDK目录

 c:\jdk1.6.0 根目录

 c:\jdk1.6.0\bin:jdk中可执行文件的目录

 c:\jdk1.6.0\lib:开发工具中会用到的一些文件     (区别jre里面的lib)

如: tools.jar它是包含一些支持jdk使用的非核心类,解压可以看到里面的内容


 同时还包含dt.jar, 决定交互开发工具(IDE)如何展示java组件



JRE的目录

c:\jdk1.6.0\jre  java运行环境的根目录,JDK开发工具会用到它。这个目录通常是系统环境变量 java.home指向的目录

c:\jdk1.6.0\jre\bin   Java平台使用的工具和类库的可执行文件和DLLs文件。这些可执行文件和/jdk1.6.0/bin中的一样。

c:\jdk1.6.0\jre\bin\client  包含Java HotSpotTM 虚拟机客户端所使用到的DLL文件

c:\jdk1.6.0\jre\bin\server  包含Java HotSpotTM 虚拟机服务端所使用到的DLL文件

c:\jdk1.6.0\jre\lib  核心类库,配置,资源文件等 (下面第5部分会提到这个的内容


如:

rt.jar :引导类 (包含java平台核心API的运行时类) rt-->runtime


charsets.jar:字符转换类

ext目录 :java平台扩展包存放的目录

还有很多这里先略



http://bbs.csdn.net/topics/340164501


http://www.cnblogs.com/echomyecho/p/3334617.html


2.运行起来

有了这个就可以运行java的程序了--------.class文件

上面bin目录中有一个java.exe ,我们调用它去运行class文件,即是开启一个JVM进程。我们的程序开启的线程等等都是在这个进程中的

注意:运行一次就是一个进程(注意不是线程),进程的特点就是:独立的资源 私有地址空间 A不能访问B地址空间)(线程则 拥有自己的堆栈,程序计数器,局部变量。但不拥有系统资源,多个线程共享父进程里的全部资源)


如果我们有一个Hello.java文件

(注:为什么我们可以直接用System这个类?因为编译器会自动帮我们import上java.lang的)参见http://blog.sina.com.cn/s/blog_56f69c6601016erf.html

先编译Hello.java得到hello.class文件,我们就可以java hello 来运行这个程序了


执行java  hello会发生什么:

(http://my.oschina.net/xianggao/blog/70826)

1)寻找jre目录,寻找jvm.dll,并初始化JVM; 

2)产生一个Bootstrap Loader(引导类加载器); 

3)Bootstrap Loader自动加载Extended Loader(扩展类加载器),并将其父Loader设为Bootstrap Loader。 

4)Bootstrap Loader自动加载AppClass Loader(系统类加载器),并将其父Loader设为Extended Loader。 

5)最后由AppClass Loader加载HelloWorld类。




3.类的生命周期


加载-------------------->连接----------------------->初始化------->使用------->  卸载

            (验证------->准备------->解析  

连接包含了验证准备解析三个过程


虚拟机规范严格规定  有且只有  5中情况必须立即对类 初始化(加载、连接自然必须已经发生)

1)遇到new  getstatic  putstatic invokestatic

2)使用java.lang.reflect包的方法使用反射对类进行调用时

3)初始化一个类,如果发现其父类还未初始化,先触发父类的初始化

4)虚拟机启动时,用户需要指定执行的主类(包含main),会初始化这个主类

5)使用JDK1.7的动态语言支持


执行java  hello就属于上面的第4种情况



4.加载器

系统提供三种加载器:

1.bootstrap classloader引导加载器 由JVM提供

(HotSpot虚拟机的引导加载器是c++编写的,JRockit和J9都有引导加载器的java类,但关键代码任然是JNI回调到C的实现)【bootstrap classloader的实例用户是获取不到的】



2.extension classloader扩展加载器 (独立于JVM之外)

3.Application classloader 系统加载器 (独立于JVM之外) (也有书里面说叫system classloader)

我们也可以自定义加载器


加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例(实例的 newInstance()方法就可以创建出该类的一个对象)

(参见http://www.ibm.com/developerworks/cn/java/j-lo-classloader/)




补充:

关于JVM是如何判定两个 Java 类是相同的: A.类的全名 B.加载此类的类加载器



5.加载过程

1)启动类加载器(Bootstrap ClassLoader):负责加载JAVA_HOME\lib目录(见上面第1部分内容)中并且能被虚拟机识别的类库到JVM内存中,如果名称不符合的类库即使放在lib目录中也不会被加载。该类加载器无法被Java程序直接引用。

URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();for(URL url:urls){System.out.println(url.toExternalForm());}

结果:file:/C:/java/jdk1.7/jre/lib/resources.jar
file:/C:/java/jdk1.7/jre/lib/rt.jar
file:/C:/java/jdk1.7/jre/lib/sunrsasign.jar
file:/C:/java/jdk1.7/jre/lib/jsse.jar
file:/C:/java/jdk1.7/jre/lib/jce.jar
file:/C:/java/jdk1.7/jre/lib/charsets.jar
file:/C:/java/jdk1.7/jre/lib/jfr.jar
file:/C:/java/jdk1.7/jre/classes

这就是引导类加载器负责加载的类(仅按文件名识别  如rt.jar   文件名不符合的即使放在lib目录下也不会被加载)

2)扩展类加载器(Extension ClassLoader):主要是负责加载JAVA_HOME\lib\ext目录中的类库,该加载器可以被开发者直接使用。

3)应用程序类加载器(Application ClassLoader):该类加载器也称为系统类加载器,它负责加载用户类路径(Classpath)上所指定的类库,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。


双亲委派模型

工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的加载器都是如此,因此所有的类加载请求都会传给顶层的启动类加载器,只有当父加载器反馈自己无法完成该加载请求(该加载器的搜索范围中没有找到对应的类)时,子加载器才会尝试自己去加载。


Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如java.lang.Object类,无论哪个类加载器去加载该类,最终都是由启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。否则的话,如果不使用该模型的话,系统中将出现多个java.lang.Object,导致混乱。

(注:即使自定义类加载器,强行使用defineClass()去加载java.lang开头的类   还是会报:java.lang.SecurityException)


ClassLoader类中loadClass()方法关键代码如下:

// First, check if the class has already been loadedClass c = findLoadedClass(name);if (c == null) {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) {// If still not found, then invoke findClass in order// to find the class.c = findClass(name);}

先检查是否已经被加载过,如果没有则调用父加载器的loadClass()方法,如果父加载器为空则默认使用启动类加载器作为父加载器。如果父类加载器加载失败,则先抛出ClassNotFoundException,然后再调用自己的findClass()方法进行加载。

6.加载器各个方法





findClass的部分代码

<span style="font-size:18px;"> byte[] classfile;InputStream in = this.getClass().getResourceAsStream(jarname);classfile = ClassPoolTail.readStream(in);return defineClass(name, classfile, 0, classfile.length);</span>

return的类型是Class<?>


0 0