1.说一下 jvm 的主要组成部分?及其作用?
类加载器(Class Loader):加载类文件到内存。Class loader只管加载,只要符合文件结构就加载,至于能否运行,它不负责,那是有Exectution Engine 负责的。
垃圾回收器:垃圾回收器可以对堆、方法区、直接内存进行回收。
执行引擎(Execution Engine):也叫解释器,负责解释命令,交由操作系统执行。
本地库接口(Native Interface):本地接口的作用是融合不同的语言为java所用
运行时数据区(Runtime Data Area):
- 堆。堆是java对象的存储区域,任何用new字段分配的java对象实例和数组,都被分配在堆上,
- 方法区:用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
- 虚拟机栈:虚拟机栈中执行每个方法的时候,都会创建一个栈桢用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
- 本地方法栈:与虚拟机发挥的作用相似,相比于虚拟机栈为Java方法服务,本地方法栈为虚拟机使用的Native方法服务,执行每个本地方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
- 程序计数器。指示Java虚拟机下一条需要执行的字节码指令。
2.栈与堆
栈存储的是局部变量,而堆存储的是实体。
3.什么是双亲委派模型?
当需要加载一个类的时候,子类加载器并不会马上去加载,而是依次去请求父类加载器加载,一直往上请求到最高类加载器:启动类加载器。当启动类加载器加载不了的时候,依次往下让子类加载器进行加载。当达到最底下的时候,如果还是加载不到该类,就会出现ClassNotFound的情况。
好处:保证了程序的安全性。例子:比如我们重新写了一个String类,加载的时候并不会去加载到我们自己写的String类,因为当请求上到最高层的时候,启动类加载器发现自己能够加载String类,因此就不会加载到我们自己写的String类了。
4.类加载的过程(5步)
加载:将java源代码编译后的.class字节码文件以二进制流的方式加载进内存
连接
验证:验证加载进来的二进制流是否符合虚拟机的规范,不会危害的虚拟机自身的安全
准备:给类变量(静态变量)赋予初始值,基本数据/引用类型数据
解析:将字符串引用转换为直接引用
初始化:变量赋予初始值、执行静态语句块、执行构造函数等等。
- 怎么判断对象是否可以被回收
可达性分析算法。目前主流的编程语言(java,C#等)的主流实现中,都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。
5.java 中都有哪些引用类型?
强引用,永远不会被删除。除非手动置null。=new,就是强引用
软引用,一些有用但是并非必需,系统发生oom之前就会被回收。
弱引用。下一次垃圾回收就会被回收,不管发不发生oom。
虚引用。为一个对象设置虚引用关联的唯一目的就是能在这个对象实例被收集器回收时收到一个系统通知。
6.说一下 jvm 有哪些垃圾回收算法?
标志清除,把要删除的标记,直接删除,易造成碎片化。
标志复制,把内存分为两块,把要删除的标记,不被删除的复制到另一端,然后删除标记的。解决碎片化,但是浪费空间。
标志整理,改进了标记清楚算法,标记后先不删除,移动到一端,再把这一端一次清理掉。
分代收集算法。老年代(要删除的少,所以采用标记整理,),新生代(不被删除的少,复制算法,8:1:1),永久代。