虚拟机执行
1、类的生命周期吗?
一个类从被加载到虚拟机内存中开始,到从内存中卸载,整个生命周期需要经过七个阶段:加载 、验证、准备、解析、初始化 、使用 和 卸载,其中验证、准备、解析三个部分统称为连接。
2、什么是类加载?类加载的过程?
类加载: 虚拟机把描述类的数据加载到内存里面,并对数据进行校验、解析和初始化,最终变成可以被虚拟机直接使用的class对象。
类加载过程如下:
- 加载:1、根据类的全限定类名获取二进制字节流;2、将字节流代表的静态存储结构转为方法区运行时存储数据结构;3、在堆中生成Class对象,作为方法区这个类数据访问入口;
- 验证: 检验加载的class文件正确性(修饰符、权限)
- 准备: 为类的静态变量分配内存并设置类变量初始值;
- 解析: 将常量池中符号引用转为直接引用(class文件常量池转至方法区运行时常量池)
- 初始化: 对类的静态变量和静态代码块执行初始化工作
3、什么是类加载器?常见的类加载器有哪些?
类加载器是指:通过一个类的全限定性类名获取该类的二进制字节流叫做类加载器。
类加载器分为以下四种:
- 启动类加载器: 用来加载java核心类库,无法被java程序直接引用;(JAVA_HOME/lib 如rt.jar)
- 扩展类加载器:用来加载java的扩展库(JAVA_HOME/jre/lib/ext)
- 系统类加载器:加载用户类路径ClassPath下的类
- 用户自定义加载器:由java语言实现,继承自ClassLoader;
4、什么是双亲委派模型?为什么需要双亲委派模型?
当一个类加载器收到一个类加载的请求,它首先不会尝试自己去加载,而是将这个请求委派给父类加载器去加载,只有父类加载器在自己的搜索范围内查找不到此类时,子加载器才会尝试自己去加载该类。
原因:
- 这是为了防止我们将来使用核心类中相同的包名和类名创建类,此时如果没有双亲委派机制,加载了我们自写的类,可能会对代码有很大影响,如果使用双亲委派机制加载了核心类库中的该类,就不会再加载相同名称的我们自写的类了,确保类加载的安全。
那怎么打破双亲委派模型?
- 自定义类加载器,继承ClassLoader类,重写loadClass方法和findClass方法。
- 线程上下文类加载器。
- Tomcat,应用的类加载器优先自行加载应用目录下的 class,并不是先委派给父加载器,加载不了才委派给父加载器。
5、热部署实现原理?
热部署概述:
- 对于Java应用程序来说,热部署就是在运行时更新Java类文件。也就是不重启服务器的情况下实现java类文件的替换修改等 。
作用:
- 可以不重启应用的情况下,更新应用。举个例子,就像电脑可以在不重启的情况下,更换U盘。
原理:
- 简单一句话让JVM重新加载新的class文件!
在类加载器中,Java类只能被加载一次,并且无法卸载。因此我们可以考虑直接把类加载器给换了,自定义类加载器,并重写ClassLoader的findClass方法。想要实现热部署可以分以下三个步骤:
- 销毁原来的自定义ClassLoader;
- 更新class类文件;
- 创建新的ClassLoader去加载更新后的class类文件。
6、Class文件结构?
7、为什么有垃圾收集还会有内存泄漏问题?
对象定义在错误的范围
- 如果长生命周期的对象持有短生命周期的引用,就很可能会出现内存泄露。
异常处理不当
- 各种资源的关闭一定要放在finally里面。
8、堆和栈有什么区别?
- 申请方式
- stack: 由系统自动分配。
- heap: 需要程序员自己申请,并指明大小
- 申请效率
- stack:由系统自动分配,速度较快,但程序员是无法控制的。
- heap:由 new 分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
- 大小限制
- stack:栈顶的地址和栈的最大容量是系统预先规定好的。
- heap:堆的大小受限于计算机系统中有效的虚拟内存,运行期间确定,因此比较灵活。
- 存贮内容
- stack:存贮局部变量表,操作数栈
- heap:存贮对象实例与数组