不合适初学者 揭秘JAVA JVM内幕

篇文章将重点分析jvm,涉及到的内容包括jvm内存模型,类加载器,GC回收算法,GC回收器,整体偏向于理论 。
本篇文章不适合初学者,适合具有3年以上开发经验的技术人员,欢迎大家一起交流分享,文章若有不足之处,欢迎读者朋友们指出,先感谢 。
一 明确jdk,jre和jvm之间关系下图为官网关于jdk,jre和jvm的架构图,从该架构图,很容易看出三者之间关系:
(1)jdk包含jre,而jre又包含jvm
(2)jdk主要用于开发环境,jre主要用于发布环境,当然,发布环境用jdk也没问题,仅仅是性能可能会有点影响,jdk与jre关系有点类似程序debug版本和release版本之间关系
(3)从文件大小来说,jdk比jre大 。从图中可以看出,jdk比jre多了一层工具包,如常用的JAVAc,java命令等

不合适初学者 揭秘JAVA JVM内幕

文章插图
 
二 类加载器关于jvm类加载器,可概括为如下图:
不合适初学者 揭秘JAVA JVM内幕

文章插图
 
1.为什么要有类加载器?
【不合适初学者 揭秘JAVA JVM内幕】(1)将字节码文件加载到运行时数据区 。.java源码通过Javac命令编译后形成的字节码文件(.class),通过类加载器加载进入jvm中的 。
(2)确定字节码文件在运行时数据区的唯一性 。相同的字节码文件,通过不同的类加载器,就形成不同的文件,因此字节码文件在运行时数据区的唯一性是由字节码文件和加载它的类加载器共同决定的
2.类加载器的种类
从种类上来划分,类加载器主要划分为四大类
(1)启动类加载器 (根类加载器Bootstrap ClassLoader):该类加载器位于类加载器的最顶层,主要加载jre核心相关jar包,如 /jre/lib/rt.jar
(2)扩展类加载器(Extension ClassLoader):该类加载器位于类加载器层次的第二层,主要加载 jre扩展相关jar包,如/jre/lib/ext/*.jar
(3)应用程序类加载器(Application ClassLoader) App:该类加载器位于类加载器的第三层,主要加载类路径(classpaht)下的相关jar包
(4)用户自定义类加载器(User ClassLoader):该类加载器为用户自定义类加载器,主要加载用户指定的路径下的相关jar包
3.类加载器的机制(双亲委派)
对于字节码的加载,类加载机制为双亲委派,什么叫双亲委派呢?
类加载器获取字节码文件后,不是直接加载,而是将该字节码文件传递给其直接父级类加载器,其直接父加载器又继续传递给其直接父加载器的直接父加载器,依次类推到根父加载器,若根父加载器
能加载,则加载,否则交给其直接孩子加载器加载,直接孩子加载器能加载就加载,若不能,依次类推其直接孩子类加载器,若都不能加载,最后才由用户自定义类加载器加载 。
4.jdk 1.8 如何实现类加载器?
如下为jdk 1.8 类加载器的实现,采用递归方式
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> 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) {// If still not found, then invoke findClass in order// to find the class.long t1 = System.nanoTime();c = findClass(name);// this is the defining class loader; record the statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}5.破坏双亲委派模型
在某些情况下,由于受加载范围限制,父类加载器无法加载到需要的文件,因此父类加载器需要委托其子类加载器去加载相应的字节码文件 。
如在jdk中定义的数据库驱动接口Driver,但该接口的实现却由不同的数据库厂商来实现,这就产生这样一个问题:由启动类(Bootstrap ClassLoader)
执行的DriverManager要加载实现了Driver接口的相关实现类,从而实现统一管理,但Bootstrap ClassLoader只能加载jre/lib下的相应文件,不能加载
由各个厂商实现的Dirver接口相关实现类(Dirver实现类是由Application ClassLoader加载),这时就需要Bootstrap ClassLoader委托其子类加载器加载Driver
来实现,从而破坏了双亲委派模型 。
三 类的生命周期java中的类,在jvm中的生命周期,大概分为五个阶段:


推荐阅读