本篇文章不适合初学者,适合具有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命令等
二 类加载器
======
关于jvm类加载器,可概括为如下图:
1.为什么要有类加载器?
(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 loaded
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) {
// 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 stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass©;
}
return c;
}
}
5.破坏双亲委派模型
在某些情况下,由于受加载范围限制,父类加载器无法加载到需要的文件,因此父类加载器需要委托其子类加载器去加载相应的字节码文件。
如在jdk中定义的数据库驱动接口Driver,但该接口的实现却由不同的数据库厂商来实现,这就产生这样一个问题:由启动类(Bootstrap ClassLoader)
执行的DriverManager要加载实现了Driver接口的相关实现类,从而实现统一管理,但Bootstrap ClassLoader只能加载jre/lib下的相应文件,不能加载
由各个厂商实现的Dirver接口相关实现类(Dirver实现类是由Application ClassLoader加载),这时就需要Bootstrap ClassLoader委托其子类加载器加载Driver
来实现,从而破坏了双亲委派模型。
三 类的生命周期
========
java中的类,在jvm中的生命周期,大概分为五个阶段:
1.加载阶段:获取字节码二进制流,并将静态存储结构转化成方法区的运行时数据结构,且在方法区生成相应的类对象(java.lang.Class对象),作为该类的数据访问入口。
2.连接阶段:该阶段包括三个小阶段,即验证,准备和解析三阶段
(1)验证:确保字节码文件符合虚拟机规范要求,如元数据验证,文件格式验证,字节码验证和符号验证等
(2)准备:为内的静态表里分配内存,并且设置jvm默认值,对于非静态变量,此阶段,不需分配内存。
(3)解析:将常量池内的符号引用转化为直接引用
3.初始化阶段:类对象使用前的一些必要初始化工作
如下引用自一位博友的观点,个人认为解释得很好。
在 Java 代码中,如果要初始化一个静态字段,我们可以在声明时直接赋值,也可以在静态代码块中对其赋值。
除了 final static 修饰的常量,直接赋值操作以及所有静态代码块中的代码,则会被 Java 编译器置于同一方法中,并把它命名为 < clinit > 。初始化的目的是是为标记为
常量值的字段赋值,以及执行< clinit > 方法的过程。Java 虚拟机会通过加锁来确保类的 < clinit > 方法仅被执行一次。
哪些条件会发生类初始化呢?
(1)当虚拟机启动时,初始化用户指定的主类(main函数);
(2)当遇到用于新建目标类实例的 new 指令时,初始化 new 指令的目标类;
(3)当遇到调用静态方法的指令时,初始化该静态方法所在的类;
(4)子类的初始化会触发父类的初始化;
(5)如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;
(6)使用反射 API 对某个类进行反射调用时,初始化这个类;
(7)当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类。
4.使用阶段:jvm中使用对象
5.卸载阶段:将对象从jvm中卸载(unload),哪些条件会使jvm发生类卸载呢?
(1)加载该类的类加载器被回收
(2)该类的所有实例已经被回收
(3)该类对应的java.lang.Class对象没有任何地方被引用
四 jvm内存模型
=========
1.JVM内存模型是怎样的?
如下为JVM内存模型架构图,由于在之前的文章中论述过,这里就不再一 一论述,主要讲解堆区。
在jdk 1.8前,堆区主要分为新生代、老年代和永久代。jdk 1.8后,去掉了永久代,增加了MetaSpace区。这里,主要分享jdk 1.8。
根据jdk1.8,堆区逻辑抽象为三个部分:
(1)新生代:包括Eden区,S0区(也叫from区),S21(也叫TO区)
(2)老年代
(3)Metaspace区
2.新生代和老年代的内存大小是怎样的?
根据官方建议,新生代占三分之一(Eden:S0:S1=8:1:1),老年代占三分之二,因此内存分配图如下:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
Java架构进阶面试及知识点文档笔记
这份文档共498页,其中包括Java集合,并发编程,JVM,Dubbo,Redis,Spring全家桶,MySQL,Kafka等面试解析及知识点整理
Java分布式高级面试问题解析文档
其中都是包括分布式的面试问题解析,内容有分布式消息队列,Redis缓存,分库分表,微服务架构,分布式高可用,读写分离等等!
互联网Java程序员面试必备问题解析及文档学习笔记
Java架构进阶视频解析合集
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
图片转存中…(img-R9Z51hEW-1713705975181)]
Java分布式高级面试问题解析文档
其中都是包括分布式的面试问题解析,内容有分布式消息队列,Redis缓存,分库分表,微服务架构,分布式高可用,读写分离等等!
[外链图片转存中…(img-nYb68NHQ-1713705975181)]
互联网Java程序员面试必备问题解析及文档学习笔记
[外链图片转存中…(img-QBE7mKxe-1713705975181)]
Java架构进阶视频解析合集
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!