java 2018面试宝典之-JVM篇(含解答)

 

目录

1 什么情况下会发生栈内存溢出。

2 JVM的内存结构,Eden和Survivor比例。

3 你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。

4 垃圾回收算法的实现原理。

5 当出现了内存溢出,你怎么排错。

6 JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存等。

7 g1和cms区别,吞吐量优先和响应优先的垃圾收集器选择。

9 内存模型以及分区,需要详细到每个区放什么。

10 堆里面的分区:新生代(Eden,survival)老年代,各自的特点。

11对象创建方法,对象的内存分配,对象的访问定位。

12 GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方。

3 你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。

4 垃圾回收算法的实现原理。

5 当出现了内存溢出,你怎么排错。

6 JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存等。

7 g1和cms区别,吞吐量优先和响应优先的垃圾收集器选择。

9 内存模型以及分区,需要详细到每个区放什么。

10 堆里面的分区:新生代(Eden,survival)老年代,各自的特点。

11对象创建方法,对象的内存分配,对象的访问定位。

12 GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方。


 

 

JVM实际的理解还很有局限性 简单放一些整理的题目 希望对大家有所帮助

什么情况下会发生栈内存溢出。

==================================================================

  内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出。如果出现这种现象可行代码排查:

一)是否App中的类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串。如public static int i = 0; //public static String str;

二)是否App中使用了大量的递归或无限递归(递归中用到了大量的建新的对象)

是否App中使用了大量循环或死循环(循环中用到了大量的新建的对象)

 ==================================================================

 

2 JVM的内存结构,Eden和Survivor比例

 ==================================================================

 

JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。

JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的JVM参
数。

 ==================================================================

 

3 你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。

 ==================================================================

串行回收器(serial collector),并行回收器,CMS回收器,G1回收器

CMS回收器:停顿时间最短,分为以下步骤:1初始标记;2并发标记;3重新标记;4并发清除。优点是停顿时间短,并发回收,缺点是无法处理浮动垃圾,而且会导致空间碎片产生。

 ==================================================================

4 垃圾回收算法的实现原理。

 ==================================================================

追踪回收算法(tracing collector)

从根结点开始遍历对象的应用图。同时标记遍历到的对象。遍历完成后,没有被标记的对象就是目前未被引用,可以被回收。

 

压缩回收算法(Compacting Collector)

把堆中活动的对象集中移动到堆的一端,就会在堆的另一端流出很大的空闲区域。这种处理简化了消除碎片的工作,但可能带来性能的损失。

 

复制回收算法(Coping Collector)

把堆均分成两个大小相同的区域,只使用其中的一个区域,直到该区域消耗完。此时垃圾回收器终端程序的执行,通过遍历把所有活动的对象复制到另一个区域,复制过程中它们是紧挨着布置的,这样也可以达到消除内存碎片的目的。复制结束后程序会继续运行,直到该区域被用完。

但是,这种方法有两个缺陷:

 

对于指定大小的堆,需要两倍大小的内存空间,

需要中断正在执行的程序,降低了执行效率

按代回收算法(Generational Collector)

为什么要按代进行回收?这是因为不同对象生命周期不同,每次回收都要遍历所有存活对象,对于整个堆内存进行回收无疑浪费了大量时间,对症下药可以提高垃圾回收的效率。主要思路是:把堆分成若搞个子堆,每个子堆视为一代,算法在运行的过程中优先收集“年幼”的对象,如果某个对象经过多次回收仍然“存活”,就移动到高一级的堆,减少对其扫描次数。

 ==================================================================

5 当出现了内存溢出,你怎么排错。

内存溢出排查步骤: 
确定是哪个内存区域溢出:是年轻代,还是老年代:通过jstat -gcutil在线看(如果年轻代都内存不断上升,并且100%,minor gc, 
但是还是不释放的场景),通过gc.log离线看

这里只是大概说下思路 实际的场景应该远不一样

6 JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存等。

内存屏障:为了保障执行顺序和可见性的一条cpu指令

重排序:为了提高性能,编译器和处理器会对执行进行重拍

happen-before:操作间执行的顺序关系。有些操作先发生。

主内存:共享变量存储的区域即是主内存

工作内存:每个线程copy的本地内存,存储了该线程以读/写共享变量的副本

简单说说你了解的类加载器,可以打破双亲委派么,怎么打破。

1:自己写一个类加载器

2:重写loadclass方法

3:重写findclass方法

这里最主要的是重写loadclass方法,因为双亲委派机制的实现都是通过这个方法实现的,先找附加在其进行加载,如果父加载器无法加载再由自己来进行加载,源码里会直接找到根加载器,重写了这个方法以后就能自己定义加载的方式了

 

双亲委派不错的参考文章:https://blog.csdn.net/moakun/article/details/81258006

 ==================================================================

 

7 g1和cms区别,吞吐量优先和响应优先的垃圾收集器选择。

 ==================================================================

Cms是以获取最短回收停顿时间为目标的收集器。基于标记-清除算法实现。比较占用cpu资源,切易造成碎片。 
G1是面向服务端的垃圾收集器,是jdk9默认的收集器,基于标记-整理算法实现。可利用多核、多cpu,保留分代,实现可预测停顿,可控。

 ==================================================================

 

 8请解释如下jvm参数的含义:
-server -Xms512m -Xmx512m -Xss1024K
-XX:PermSize=256m -XX:MaxPermSize=512m -
XX:MaxTenuringThreshold=20XX:CMSInitiatingOccupancyFraction=80 -
XX:+UseCMSInitiatingOccupancyOnly。

Server模式启动  最小堆内存512m  最大512m  每个线程栈空间1m 
永久代256  最大永久代256 
最大转为老年代检查次数20  Cms回收开启时机:内存占用80% 
命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期

 ==================================================================

9 内存模型以及分区,需要详细到每个区放什么。

堆:Java虚拟机管理内存中最大的一块,线程共享区域。所有对象实例和数组都在堆上分配内存空间。

栈:线程私有,每个线程都会创建一个虚拟机栈,生命周期与线程相同。每个方法被执行的时候就会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。一个方法执行的过程对应着一个栈帧的入栈到出栈过程。

方法区:用于存储类信息,常量,静态变量等信息,是线程共享区域。

程序计数器:一块较小的内存空间,作用是当前执行字节码的行号指示器。

 ==================================================================

10 堆里面的分区:新生代(Eden,survival)老年代,各自的特点。

堆中存储对象实例,是垃圾回收的主要区域。为了方便垃圾回收,将堆区域分为新生代和老年代两个区域。

新生代:大量对象(98%)都是朝生夕死,因此在进行垃圾回收的时候采用复制算法进行垃圾回收,因为只需付出商量存货对象的复制成本就可以完成收集。但是由于新生代大量对象都是非存活状态,按照常规复制算法1:1划分内存会造成大量空间的浪费。因此新生代又可以划分为一块较大的Eden区域和两块较小的Survivor空间,每次使用Eden和其中一块Survivor区域。回收时,将存活的对象一次性拷贝到另一块Survivor空间上,再清理掉用过的Eden和Survivor空间。默认Eden区域:Survivor区域=8:1 也就是每次使用新生代容量的90%,只有10%被浪费。但是当Survivor区域不足 以存储回收后存活的对象时,需要老年代进行空间担保,这些对象直接通过分配担保机制进入老年代。

老年代:判断对象是否死亡,至少进行两次标记过程。如果对象在Eden出生并且经过一次gc后仍然存活,并且能够被Survivor容纳的话,将会被移动到Survivor区域,并将其年龄设置为1,如果它还能熬过下一次gc收集,年龄再+1.默认情况下当年龄到达15后,就会晋升到老年代中。老年代采用标记清除和标记整理算法进行垃圾收集。

 ==================================================================

11对象创建方法,对象的内存分配,对象的访问定位。

虚拟机遇到一个new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,需要先执行相应的类加载过程。 

对象访问定位符:

1.句柄访问方式:java堆中划分一部分空间作为句柄池,栈reference中存储对象的句柄地址,句柄中包含对象实例数据和各自对象具体地址。即对象实 例数据指针指向堆的实例池对象地址、对象类型数据指针指向方法区的对象类型数据。

优势:reference中存在稳定的句柄地址。对象被移动时只改变句柄中实例数据指针。

2.直接指针访问方式: reference中直接存储对象实例地址,对象实例数据中有一小块区域存储对象类型数据指针,同样指向方法区。

优势:节省了一次指针定位的开销,访问速度更快。

 ==================================================================

12 GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方。

1.标记清除算法:首先标记处所有需要回收的对象,在标记完成后统一进行回收。

缺点:标记的过程效率不高、标记清除之后产生大量不连续的内存碎片,当需要申请大块连续内存空间时,无法找到。

2.复制算法:将内存按容量费为大小相等的两块区域,每次只使用其中的一块,当一块内存用完了,就将还存活的对象复制到另一块内存上面,然后吧使用过的那块内存统一清理掉。

缺点:每次只能使用总内存容量的一半。在对象存活较多的情况下会进行大量复制操作,效率底下。

3.标记整理算法:和标记清除算法一样,先对死亡对象进行标记,然后将存活对象向一端移动,然后直接清理掉边界以外的内存。

4.分代收集算法:根据对象存活周期的不同,将内存划分为新生代和老年代,新生代使用复制算法,老年代使用标记清除或标记整理算法进行垃圾收集。

 ==================================================================

13  Minor GC与Full GC分别在什么时候发生? 
Minor GC: 从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。 
特点:当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。所以分配率越高,越频繁执行 Minor G。内存池被填满的时候,其中的内容全部会被复制,指针会从0开始跟踪空闲内存。Eden 和 Survivor 区进行了标记和复制操作,取代了经典的标记、扫描、压缩、清理操作。所以 Eden 和 Survivor 区不存在内存碎片。写指针总是停留在所使用内存池的顶部。 
执行 Minor GC 操作时,不会影响到永久代。从永久代到年轻代的引用被当成 GC roots,从年轻代到永久代的引用在标记阶段被直接忽略掉。 
质疑常规的认知,所有的 Minor GC 都会触发“全世界的暂停(stop-the-world)”,停止应用程序的线程。对于大部分应用程序,停顿导致的延迟都是可以忽略不计的。其中的真相就 是,大部分 Eden 区中的对象都能被认为是垃圾,永远也不会被复制到 Survivor 区或者老年代空间。如果正好相反,Eden 区大部分新生对象不符合 GC 条件,Minor GC 执行时暂停的时间将会长很多。

Major GC:清理永久代

Full GC:清理整个堆空间—包括年轻代和永久代

Major GC / Full GC:老年代 GC(Major GC / Full GC):指发生在老年代的 GC,出现了 Major GC,经常会伴随至少一次的 Minor GC(但非绝对的,在 ParallelScavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程) 。MajorGC 的速度一般会比 Minor GC 慢 10倍以上。

  1. 什么情况下会发生栈内存溢出。==================================================================

  内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出。如果出现这种现象可行代码排查:

一)是否App中的类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串。如public static int i = 0; //public static String str;

二)是否App中使用了大量的递归或无限递归(递归中用到了大量的建新的对象)

是否App中使用了大量循环或死循环(循环中用到了大量的新建的对象)

 ==================================================================

 

2 JVM的内存结构,Eden和Survivor比例

 ==================================================================

 

JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。

JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的JVM参
数。

 ==================================================================

 

3 你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。

 ==================================================================

串行回收器(serial collector),并行回收器,CMS回收器,G1回收器

CMS回收器:停顿时间最短,分为以下步骤:1初始标记;2并发标记;3重新标记;4并发清除。优点是停顿时间短,并发回收,缺点是无法处理浮动垃圾,而且会导致空间碎片产生。

 ==================================================================

4 垃圾回收算法的实现原理。

 ==================================================================

追踪回收算法(tracing collector)

从根结点开始遍历对象的应用图。同时标记遍历到的对象。遍历完成后,没有被标记的对象就是目前未被引用,可以被回收。

 

压缩回收算法(Compacting Collector)

把堆中活动的对象集中移动到堆的一端,就会在堆的另一端流出很大的空闲区域。这种处理简化了消除碎片的工作,但可能带来性能的损失。

 

复制回收算法(Coping Collector)

把堆均分成两个大小相同的区域,只使用其中的一个区域,直到该区域消耗完。此时垃圾回收器终端程序的执行,通过遍历把所有活动的对象复制到另一个区域,复制过程中它们是紧挨着布置的,这样也可以达到消除内存碎片的目的。复制结束后程序会继续运行,直到该区域被用完。

但是,这种方法有两个缺陷:

 

对于指定大小的堆,需要两倍大小的内存空间,

需要中断正在执行的程序,降低了执行效率

按代回收算法(Generational Collector)

为什么要按代进行回收?这是因为不同对象生命周期不同,每次回收都要遍历所有存活对象,对于整个堆内存进行回收无疑浪费了大量时间,对症下药可以提高垃圾回收的效率。主要思路是:把堆分成若搞个子堆,每个子堆视为一代,算法在运行的过程中优先收集“年幼”的对象,如果某个对象经过多次回收仍然“存活”,就移动到高一级的堆,减少对其扫描次数。

 ==================================================================

5 当出现了内存溢出,你怎么排错。

内存溢出排查步骤: 
确定是哪个内存区域溢出:是年轻代,还是老年代:通过jstat -gcutil在线看(如果年轻代都内存不断上升,并且100%,minor gc, 
但是还是不释放的场景),通过gc.log离线看

这里只是大概说下思路 实际的场景应该远不一样

6 JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存等。

内存屏障:为了保障执行顺序和可见性的一条cpu指令

重排序:为了提高性能,编译器和处理器会对执行进行重拍

happen-before:操作间执行的顺序关系。有些操作先发生。

主内存:共享变量存储的区域即是主内存

工作内存:每个线程copy的本地内存,存储了该线程以读/写共享变量的副本

简单说说你了解的类加载器,可以打破双亲委派么,怎么打破。

1:自己写一个类加载器

2:重写loadclass方法

3:重写findclass方法

这里最主要的是重写loadclass方法,因为双亲委派机制的实现都是通过这个方法实现的,先找附加在其进行加载,如果父加载器无法加载再由自己来进行加载,源码里会直接找到根加载器,重写了这个方法以后就能自己定义加载的方式了

 

双亲委派不错的参考文章:https://blog.csdn.net/moakun/article/details/81258006

 ==================================================================

 

7 g1和cms区别,吞吐量优先和响应优先的垃圾收集器选择。

 ==================================================================

Cms是以获取最短回收停顿时间为目标的收集器。基于标记-清除算法实现。比较占用cpu资源,切易造成碎片。 
G1是面向服务端的垃圾收集器,是jdk9默认的收集器,基于标记-整理算法实现。可利用多核、多cpu,保留分代,实现可预测停顿,可控。

 ==================================================================

 

 8请解释如下jvm参数的含义:
-server -Xms512m -Xmx512m -Xss1024K
-XX:PermSize=256m -XX:MaxPermSize=512m -
XX:MaxTenuringThreshold=20XX:CMSInitiatingOccupancyFraction=80 -
XX:+UseCMSInitiatingOccupancyOnly。

Server模式启动  最小堆内存512m  最大512m  每个线程栈空间1m 
永久代256  最大永久代256 
最大转为老年代检查次数20  Cms回收开启时机:内存占用80% 
命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期

 ==================================================================

9 内存模型以及分区,需要详细到每个区放什么。

堆:Java虚拟机管理内存中最大的一块,线程共享区域。所有对象实例和数组都在堆上分配内存空间。

栈:线程私有,每个线程都会创建一个虚拟机栈,生命周期与线程相同。每个方法被执行的时候就会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。一个方法执行的过程对应着一个栈帧的入栈到出栈过程。

方法区:用于存储类信息,常量,静态变量等信息,是线程共享区域。

程序计数器:一块较小的内存空间,作用是当前执行字节码的行号指示器。

 ==================================================================

10 堆里面的分区:新生代(Eden,survival)老年代,各自的特点。

堆中存储对象实例,是垃圾回收的主要区域。为了方便垃圾回收,将堆区域分为新生代和老年代两个区域。

新生代:大量对象(98%)都是朝生夕死,因此在进行垃圾回收的时候采用复制算法进行垃圾回收,因为只需付出商量存货对象的复制成本就可以完成收集。但是由于新生代大量对象都是非存活状态,按照常规复制算法1:1划分内存会造成大量空间的浪费。因此新生代又可以划分为一块较大的Eden区域和两块较小的Survivor空间,每次使用Eden和其中一块Survivor区域。回收时,将存活的对象一次性拷贝到另一块Survivor空间上,再清理掉用过的Eden和Survivor空间。默认Eden区域:Survivor区域=8:1 也就是每次使用新生代容量的90%,只有10%被浪费。但是当Survivor区域不足 以存储回收后存活的对象时,需要老年代进行空间担保,这些对象直接通过分配担保机制进入老年代。

老年代:判断对象是否死亡,至少进行两次标记过程。如果对象在Eden出生并且经过一次gc后仍然存活,并且能够被Survivor容纳的话,将会被移动到Survivor区域,并将其年龄设置为1,如果它还能熬过下一次gc收集,年龄再+1.默认情况下当年龄到达15后,就会晋升到老年代中。老年代采用标记清除和标记整理算法进行垃圾收集。

 ==================================================================

11对象创建方法,对象的内存分配,对象的访问定位。

虚拟机遇到一个new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,需要先执行相应的类加载过程。 

对象访问定位符:

1.句柄访问方式:java堆中划分一部分空间作为句柄池,栈reference中存储对象的句柄地址,句柄中包含对象实例数据和各自对象具体地址。即对象实 例数据指针指向堆的实例池对象地址、对象类型数据指针指向方法区的对象类型数据。

优势:reference中存在稳定的句柄地址。对象被移动时只改变句柄中实例数据指针。

2.直接指针访问方式: reference中直接存储对象实例地址,对象实例数据中有一小块区域存储对象类型数据指针,同样指向方法区。

优势:节省了一次指针定位的开销,访问速度更快。

 ==================================================================

12 GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方。

1.标记清除算法:首先标记处所有需要回收的对象,在标记完成后统一进行回收。

缺点:标记的过程效率不高、标记清除之后产生大量不连续的内存碎片,当需要申请大块连续内存空间时,无法找到。

2.复制算法:将内存按容量费为大小相等的两块区域,每次只使用其中的一块,当一块内存用完了,就将还存活的对象复制到另一块内存上面,然后吧使用过的那块内存统一清理掉。

缺点:每次只能使用总内存容量的一半。在对象存活较多的情况下会进行大量复制操作,效率底下。

3.标记整理算法:和标记清除算法一样,先对死亡对象进行标记,然后将存活对象向一端移动,然后直接清理掉边界以外的内存。

4.分代收集算法:根据对象存活周期的不同,将内存划分为新生代和老年代,新生代使用复制算法,老年代使用标记清除或标记整理算法进行垃圾收集。

 ==================================================================

13  Minor GC与Full GC分别在什么时候发生? 
Minor GC: 从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。 
特点:当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。所以分配率越高,越频繁执行 Minor G。内存池被填满的时候,其中的内容全部会被复制,指针会从0开始跟踪空闲内存。Eden 和 Survivor 区进行了标记和复制操作,取代了经典的标记、扫描、压缩、清理操作。所以 Eden 和 Survivor 区不存在内存碎片。写指针总是停留在所使用内存池的顶部。 
执行 Minor GC 操作时,不会影响到永久代。从永久代到年轻代的引用被当成 GC roots,从年轻代到永久代的引用在标记阶段被直接忽略掉。 
质疑常规的认知,所有的 Minor GC 都会触发“全世界的暂停(stop-the-world)”,停止应用程序的线程。对于大部分应用程序,停顿导致的延迟都是可以忽略不计的。其中的真相就 是,大部分 Eden 区中的对象都能被认为是垃圾,永远也不会被复制到 Survivor 区或者老年代空间。如果正好相反,Eden 区大部分新生对象不符合 GC 条件,Minor GC 执行时暂停的时间将会长很多。

Major GC:清理永久代

Full GC:清理整个堆空间—包括年轻代和永久代

Major GC / Full GC:老年代 GC(Major GC / Full GC):指发生在老年代的 GC,出现了 Major GC,经常会伴随至少一次的 Minor GC(但非绝对的,在 ParallelScavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程) 。MajorGC 的速度一般会比 Minor GC 慢 10倍以上。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值