1.介绍一下JVM的内存结构
JDK1.8及以后,JVM主要分为元空间、堆、虚拟机栈、本地方法栈、程序计数器五个部分,另外还有一个直接内存部分,是直接属于操作系统的。
其中元空间、堆是线程共享的,虚拟机栈、本地方法栈、程序计数器是线程私有的。
元空间:主要存储的是Java中类的信息,包括类名、常量池、类的字段和方法等。
堆:存储的是各种对象,垃圾回收(GC)的主要区域。
虚拟机栈:主要存储的是局部变量表、操作数栈、动态链接、方法返回地址。
本地方法栈:存储的是本地native方法的局部变量表、操作数栈、动态链接、方法返回地址。
2.JDK1.7之前和1.8之后的JVM的区别
JDK1.7以前,永久代位于堆内,使用虚拟机内存,是一个固定大小的区域,很容易超出内存,会产生OutOfMemoryError的错误,并且位于虚拟机内存时,垃圾回收(GC)的效率非常低。
JDK1.8之后,元空间替代了永久代,以往方法区的永久代是位于堆内部的,JDK1.8的元空间位于堆外,不使用虚拟机的内存而是本地内存。
3.JVM的类加载过程
JVM的类加载过程分为加载验证、准备、解析、初始化五个步骤,其中验证、准备、解析统称为连接。
4.类加载器有哪些
自上而下,类加载器分别有BootStrapClassLoader(启动类加载器)、ExtensionClassLoader(扩展类加载器)、ApplicationClassLoader(启动类加载器)、UserClassLoader(用户自定义 加载器)。
5.介绍一下JVM的双亲委派机制以及作用
双亲委派机制指当类加载器受到加载请求时,不是先自己尝试加载这个类,而是把它交给自己的父类加载器去处理,依次到顶层的类加载器,如果父类加载器没有搜索到这个类,再交给子类加载器去加载。
作用:①保证Java核心类的唯一性,用户自己如果写相同名称的类也不会使核心类无法使用。
②提高了安全性,防止不可信的类假冒核心类。
6.GC是什么,什么时候触发GC
GC是指JVM自动地对一些不使用的对象进行垃圾回收。
GC的触发机制通常有:内存不足;手动请求,比如调用System.gc();
7.判断垃圾的方法有哪些
判断垃圾回收主要有以下两种方法:
①引用计数器法,即每个对象都具有一个引用计数器,每被其他对象引用一次就+1,引用失效就-1。
这种方法最大的缺陷就是无法解决循环引用的问题,及两个对象相互引用。所以JVM采用的使用下一种方法
②可达性分析法,从一组称为GCRoot的对象开始,依次向下寻找引用的对象,能寻找到的对象均视为可达,最后仍然为不可达的对象就被视为垃圾。
8.垃圾回收的方式有哪些
常见的垃圾回收方式有以下四种:
①标记-清除,通过可达性分析算法进行标记,没有被标记到的视为垃圾,并一起进行垃圾回收。这样的坏处在于会产生大量的内存碎片。
②复制,内存只使用一半,回收时将存活的对象复制到另一半的内存中,同时清除掉这一半所有的对象。这样的坏处在于内存的利用率太低。
③标记-整理,标记与前面所说相同,标记完成后,将没有标记到的垃圾对象移到内存的一侧,一起清除,这样就不会产生内存碎片。
④分代回收:按照存活时间将对象分为新生代和老年代(根据经历GC回收的次数,一般是经过15次后变为老年代),对它们采用不同的回收方式,如JDK1.8就是对于新生代采用复制,对老年代采用标记整理。
9.常见的垃圾回收器有哪些
JDK 8: Parallel Scavenge(新生代)+ Parallel Old(老年代)
JDK 9 ~ JDK22: G1
① Serial:最早版本,串行执行,新生代采用标记-复制算法,老年代采用标记-整理算法。
② ParNew:是Serial的多线程版本。
③ Parallel Scavenge: ParNew的优化版本,提供了很多参数供用户找到最合适的停顿时间或最大吞吐量。
④ Parallel Old:Parallel Scavenge 收集器的老年代版本。使用多线程和“标记-整理”算法。
⑤ CMS:针对老年代是一种以获取最短回收停顿时间为目标的收集器,使用的方法是标记-清除。
⑥G1:G1 (Garbage-First) 是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器.,以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征。回收方法采用标记整理,包括:初始标记,并发标记,最终标记,筛选回收。
10.G1与CMS的对比
①:CMS只针对于老年代,G1收集范围是老年代和新生代。
②:CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片,G1使用的是标记-整理,不会产生内存碎片。
③ :G1可预测停顿,建立可预测的停顿时间模型。
④:G1 能充分利用 CPU、多核环境下的硬件优势,使用多个CPU工作来缩短停顿时间。
11.内存泄漏和内存溢出分别是什么
内存泄漏指程序在运行过程中,不再使用的对象仍然被引用,因此也无法被GC回收掉的情况,最终会导致程序的性能下降。
常见的内存泄漏的情况有:使用静态集合(ArrayList、HashMap)存储对象,因为只要类被加载静态集合就存在;未取消对事件源的监听;未停止的线程可能持有对象引用。
内存溢出指程序在申请内存时所需要的内存过大,无法申请成功的情形
常见原因:深度递归、死循环会导致栈溢出;程序中不断创建大量对象,超出JVM堆的限制;一些大型的数据结构一直引用对象,无法被回收。