JVM面经

1.管理JVM工作的多线程有哪些  即JVM的工作原理

#JVM组成:类加载子系统,运行时数据区,执行引擎,本地方法接口,本地方法库

 

2.classloader 有两种装载class的方式 (时机):

隐式:运行过程中,碰到new方式生成对象时,隐式调用classLoader到JVM

显式:通过class.forname()动态加载

 

3.破坏双亲委派模型

父类加载器请求子类加载器去完成类加载的动作,如JNDIJDBCSPI操作,基础类需要调用实现类的方法。通过线程上下文(应用)类加载器实现。

JNDI启动类加载器需要调用应用类加载器中的方法。

 

4.JVM具体会在什么时候进行垃圾回收?JMM具体说说?

垃圾回收算法具体说说?各种垃圾回收器了解吗?什么时候执行STOP THE WORLD?

 

5.JMM(java memory model)

程序计数器,栈,本地方法栈,堆,方法区。

在JVM内部使用的java内存模型(JMM)将线程栈和堆之间的内存分开。

堆中的共享变量需要有volatile和synchronized保证线程安全。

 

6.cms垃圾收集器

#标记-清除:初始标记,并发标记,重新标记,并发清除。

 初始标记、重新标记这两个步骤需要stop the world”

初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快。

并发标记阶段就是进行GC Roots Tracing。

重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生表动的那一部分对象的标记记录。

主要优点:并发收集、低停顿。

缺点:CMS是一款“标记--清除”算法实现的收集器,容易出现大量空间碎片。

G1垃圾收集器

#初始标记;并发标记;最终标记;筛选回收

初始标记阶段仅仅只是标记一下GC Roots能直接关联到的对象。

并发标记阶段是从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段时耗时较长。

最终标记阶段则是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录。

优点:并行于并发,分代收集,空间整合(整体来看是基于“标记整理”,局部上来看是基于“复制”),可预测的停顿。

 

7.堆中的对象是如何调用方法的

通过class类对象

 

8.内存泄漏

    不再会被使用的对象的内存不能被回收,就是内存泄露。如果长生命周期的对象持有短生命周期的引用,就很可能会出现内存泄露。

public class Simple {

    Object object;

    public void method1(){

        object = new Object();

        //...其他代码

        object = null; //没这句话,method只执行一次后new Object()无法被回收

    }

}

     定位内存泄漏的方法:通过监测 Java 程序运行时,所有对象的申请、释放等动作,将内存管理的所有信息进行统计、分析、可视化。

 

9.OOM(out of Memory)

#只要是申请内存时,内存不足都会发生

利用软引用和弱引用避免OOM

  下面举个例子,假如有一个应用需要读取大量的本地图片,如果每次读取图片都从硬盘读取,则会严重影响性能,但是如果全部加载到内存当中,又有可能造成内存溢出,此时使用软引用可以解决这个问题。设计思路是:用一个HashMap来保存图片的路径 和 相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。在Android开发中对于大量图片下载会经常用到。

 

10.类加载

#加载、链接(验证、准备、解析),初始化、使用和卸载

        加载:全限定名得二进制流,静态存储结构转化为方法区的运行时数据结构,堆中建立java.lang.Class对象作为对方法区数据访问的接口。

 

11.类对象

#方法区的访问入口,保存了类信息。

 

12.类什么时候会被加载

#new,静态,反射,父类,main

a.创建类的实例

b.访问类的静态变量,访问类的静态方法

c.反射

d.当初始化一个类时发现其父类还未初始化则先出发父类的初始化

e.虚拟机启动时定义了main()方法的那个类先初始化。

 

13.类加载的顺序

a.类从顶至底的顺序初始化,所以声明在顶部的字段的早于底部的字段初始化

b.超类早于子类和衍生类的初始化

c.如果类的初始化是由于访问静态域而触发,那么只有声明静态域的类才被初始化,而不会触发超类的初始化或者子类的。

d.初始化即使静态域被子类或子接口或者它的实现类所引用。

e.接口初始化不会导致父接口的初始化。

f.静态域的初始化是在类的静态初始化期间,非静态域的初始化时在类的实例创建期间。这意味这静态域初始化在非静态域之前。

g.非静态域通过构造器初始化,子类在做任何初始化之前构造器会隐含地调用父类的构造器,他保证了非静态或实例变量(父类)初始化早于子类

 

14.类加载器

       启动类加载器、扩展类加载器、应用类加载器、自定义类加载器。

     为什么能通过类名调用静态。静态属于类的(公有的),非静态要与对象绑定。

 

15.Java内存,垃圾回收机制

       那些内存需要回收?(可达性分析算法)

       什么时候回收? (堆的新生代、老年代、永久代的垃圾回收时机,MinorGC 和 FullGC)

       如何回收?(三种经典垃圾回收算法(标记清除算法、复制算法、标记整理算法)及分代收集算法 和 七种垃圾收集器)

       当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是不可用的(此对象就是内存垃圾)。

JVM面经_第1张图片

 

 

      

JVM面经_第2张图片

   一般而言,对象主要分配在新生代的Eden区上。大对象直接进入老年代,长期存活的对象(多次GC后)将进入老年代。将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。 当进行垃圾回收时,将Eden和Survivor中还存活的对象一次性地复制到另外一块Survivor空间上,最后处理掉Eden和刚才的Survivor空间。

       内存泄露是指该内存空间使用完毕之后未回收,在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度。

      强引用(一般写的代码),软引用(内存不够时回收),弱引用(发生GC就回收),虚引用(对象被回收时收到系统通知)。

        判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面3个条件才能算是“无用的类”:

a.该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例;无实例

b.加载该类的ClassLoader已经被回收;无加载器

c.该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。无类对象

        垃圾回收有两种类型,Minor GC 和 Full GC。Minor GC:对新生代进行回收,不会影响到年老代,Eden满时就会发生。Full GC:也叫 Major GC,对整个堆进行回收,包括新生代和老年代。导致Full GC的原因包括:老年代被写满、永久代(Perm)被写满和System.gc()被显式调用等。

 

16.新生代:Eden+2个Survivor 。老年代区。

        如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。

       设置两个Survivor区最大的好处就是解决了碎片化。直接把Eden中存活的对象放进Survivor中,两个区对象有可能不匹配,产生内存碎片。而把Eden+Survivor整合后放进另一个新的Survivor就能解决碎片化。

 

17.垃圾回收时可做GC Root的对象

#虚拟机栈中引用的对象,本地方法栈中引用的对象,静态,常量池。

 

 

 

 

 

 

 

你可能感兴趣的:(#,JVM,JVM面经,JVM)