面试简单整理之JVM
194.说一下 jvm 的主要组成部分?及其作用?
JVM内存分为“堆”、“栈”和“方法区”三个区域,分别用于存储不同的数据。
堆内存用于存储使用new关键字所创建的对象;
栈内存用于存储程序运行时在方法中声明的所有的局部变量;
方法区用于存放类的信息。
Java程序运行时,首先会通过类装载器载入类文件的字节码信息,经过解析后将其装入方法区。类的各种信息(包括方法)都在方法区存储。
195.说一下 jvm 运行时数据区?
Java堆
堆内存用来存放由new创建的对象实例和数组。(重点)
Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例 。
Java堆是垃圾收集器管理的主要区域。由于现在收集器基本采用分代回收算法,所以Java堆还可细分为:新生代和老年代。从内存分配的角度来看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区(TLAB)。
Java堆可以处于物理上不连续的内存空间,只要逻辑上连续的即可。在实现上,既可以实现固定大小的,也可以是扩展的。
如果堆中没有内存完成实例分配,并且堆也无法完成扩展时,将会抛出OutOfMemoryError异常。
Java栈
在栈内存中保存的是堆内存空间的访问地址,或者说栈中的变量指向堆内存中的变量(Java中的指针)(重点)。
Java栈是Java方法执行的内存模型每个方法在执行的同时都会创建一个栈帧的用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程就对应着一个栈帧在虚拟机中入栈和出栈的过程。
方法区 方法区是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据 (重点)。
相对而言,垃圾收集行为在这个区域比较少出现,但并非数据进了方法区就永久的存在了,这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,
当方法区无法满足内存分配需要时,将抛出OutOfMemoryError异常。
运行时常量池:
是方法区的一部分,它用于存放编译期生成的各种字面量和符号引用。
jdk8之后移除方法区,变为元空间,大小取决于本地的内存。
196.说一下堆栈的区别?
197.队列和栈是什么?有什么区别?
队列和栈是两种不同的数据结构。它们有以下区别: (1)操作的名称不同。队列的插入称为入队,队列的删除称为出队。栈的插入称为进栈,栈的删除称为出栈。 (2)可操作的方式不同。队列是在队尾入队,队头出队,即两边都可操作。而栈的进栈和出栈都是在栈顶进行的,无法对栈底直接进行操作。 (3)操作的方法不同。队列是先进先出(FIFO),即队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾(不能从中间插入),每次离开的成员总是队列头上(不允许中途离队)。而栈为后进先出(LIFO),即每次删除(出栈)的总是当前栈中最新的元素,即最后插入(进栈)的元素,而最先插入的被放在栈的底部,要到最后才能删除。
198.什么是双亲委派模型?
原理:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。
好处:避免重复加载类;房子核心api被篡改
199.说一下类加载的执行过程?
类加载分为三个步骤:加载,连接,初始化; 加载 根据一个类的全限定名(如cn.edu.hdu.test.HelloWorld.class)来读取此类的二进制字节流到JVM内部;将字节流所代表的静态存储结构转换为方法区的运行时数据结构(hotspot选择将Class对象存储在方法区中,Java虚拟机规范并没有明确要求一定要存储在方法区或堆区中) 转换为一个与目标类型对应的java.lang.Class对象; 连接 验证 验证阶段主要包括四个检验过程:文件格式验证、元数据验证、字节码验证和符号引用验证; 准备 为类中的所有静态变量分配内存空间,并为其设置一个初始值(由于还没有产生对象,实例变量将不再此操作范围内); 解析 将常量池中所有的符号引用转为直接引用(得到类或者字段、方法在内存中的指针或者偏移量,以便直接调用该方法)。这个阶段可以在初始化之后再执行。 初始化 在连接的准备阶段,类变量已赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员自己写的逻辑去初始化类变量和其他资源
200.怎么判断对象是否可以被回收?
通过可达性分析算法遍历所有节点,没有用到的节点即使可以回收的对象
可作为根对象有4种:虚拟机栈中的引用的对象;方法区中的静态引用;常量引用,就是使用了static final关键字;本地方法栈中引用的对象
201.java 中都有哪些引用类型?
强引用,软引用,弱引用,虚引用
202.说一下 jvm 有哪些垃圾回收算法?
1.标记-清除算法(Mark-Sweep) 标记-清除算法采用从根集合(GC Roots)进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象,进行回收,如下图所示。标记-清除算法不需要进行对象的移动,只需对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但由于标记-清除算法直接回收不存活的对象,因此会造成内存碎片。 2.复制算法(Copying) 复制算法的提出是为了克服句柄的开销和解决内存碎片的问题。它开始时把堆分成 一个对象 面和多个空闲面, 程序从对象面为对象分配空间,当对象满了,基于copying算法的垃圾 收集就从根集合(GC Roots)中扫描活动对象,并将每个 活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。 3. 标记-整理算法(Mark-compact) 标记-整理算法采用标记-清除算法一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存碎片的问题。 4.分代收集算法 分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),在堆区之外还有一个代就是永久代(Permanet Generation)。老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。 年轻代(Young Generation)的回收算法 (回收主要以Copying为主) 年老代(Old Generation)的回收算法(回收主要以Mark-Compact为主) 持久代(Permanent Generation)的回收算法 持久代(方法区)主要回收的内容有:废弃常量和无用的类。对于废弃常量也可通过引用的可达性来判断,但是对于无用的类则需要同时满足下面3个条件: 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例; 加载该类的ClassLoader已经被回收; 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
203.说一下 jvm 有哪些垃圾回收器?
Serial收集器(复制算法) 新生代单线程收集器,标记和清理都是单线程,优点是简单高效。是client级别默认的GC方式,可以通过-XX:+UseSerialGC来强制指定。 Serial Old收集器(标记-整理算法) 老年代单线程收集器,Serial收集器的老年代版本。 ParNew收集器(停止-复制算法) 新生代收集器,可以认为是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现。 Parallel Scavenge收集器(停止-复制算法) 并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般为99%, 吞吐量= 用户线程时间/(用户线程时间+GC线程时间)。适合后台应用等对交互相应要求不高的场景。是server级别默认采用的GC方式,可用-XX:+UseParallelGC来强制指定,用-XX:ParallelGCThreads=4来指定线程数。 Parallel Old收集器(停止-复制算法) Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量优先。 CMS(Concurrent Mark Sweep)收集器(标记-清理算法) 高并发、低停顿,追求最短GC回收停顿时间,cpu占用比较高,响应时间快,停顿时间短,多核cpu 追求高响应时间的选择
204.详细介绍一下 CMS 垃圾回收器?
CMS是一款并发、使用标记-清除算法的gc。CMS是针对老年代进行回收的GC。
205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
206.简述分代垃圾回收器是怎么工作的?
分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。
在Java程序运行的过程中,会产生大量的对象,其中有些对象是,比如Http请求中的Session对象、线程、Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长。但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会比较短,比如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象甚至只用一次即可回收。
因此,分代垃圾回收采用分治的思想,进行代的划分,把不同生命周期的对象放在不同代上,不同代上采用最适合它的垃圾回收方式进行回收。
年轻代:因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden区能尽快空闲出来。
年老代:年老代上选择的垃圾回收算法则取决于JVM上采用的是什么垃圾回收器,通过的垃圾回收器有两种:Parallel Scavenge(PS) 和Concurrent Mark Sweep(CMS)。
207.说一下 jvm 调优的工具?
JDK本身提供了很丰富的性能监控工具,除了集成式的visualVM和jConsole外,还有jstat,jstack,jps,jmap,jhat小工具,这些都是性能调优的常用工具
208.常用的 jvm 调优的参数都有哪些?
内存、垃圾回收相关的一些参数设置: 堆大小、比例,回收器的选择