Java面试(2)——JVM

125 阅读5分钟

综述:类加载的过程 从.java文件,通过类的加载器(在这里为字节码文件,为可移植性提供基础),加载进JVM中,加载进JVM的方法区中。 当new 一个对象时,识别new这个操作,会检查对应的类是否加载,对应的方法区的为类的模板,通过模板来生成类的实例,类的实例保存在虚拟机栈(JAVA栈)中

一、JVM外,类加载器

1、类加载器的种类

  • bootstrapClassLoader
  • ExtensionClassLoader
  • ApplicationClassLoader
  • CustromClassLoader

2、双亲委派机制

  • 原理:
  • 解决的问题:保护沙箱环境的安全
  • 总结:我爸是李刚,有事找我爸

二、JVM内

1、线程私有

  • JAVA栈或虚拟机栈
  • 本地方法栈
  • PC

2、线程共享

  • 方法区

三、垃圾回收机制(主要是对堆内的垃圾回收)

1、关于方法区在JDK7和JDK8中的不同表现

-JDK7方法区为永久代 堆和方法区在一块 -JDK8方法区为元空间 在内存中,分开

  • 优化:在一起其中一个回收,则另一个进行回收

2、关于堆内存的分配

  • 1/3是年轻代,剩余为老年代
  • 其中新生代又分为Eden区、from区和to区(两个可以互换,谁为空时谁为to)
  • 内存大小可以调节 -xms -xmx调节堆内存的大小

3、垃圾回收算法

  • 复制算法 (对应年轻代的回收)
  • 标记清除 (对应老年代的回收)
  • 标记整理 (对应老年代的回收)

4、垃圾回收器(基本忘记)

1、CMS(Concurrent Mark Sweep 并发标记清除 )(垃圾回收器实现了垃圾回收算法) 标记清除

主要流程如下:

  • 初始标记 STW(Stop the world) GC过程中应用的程序会发生停顿 将老年代的死的标出来,还有就是跨代引用的(注意:因为使用的可达性分析法,但这次指指向root) STW
  • 并发标记 将GCROOT下面的进行追溯 (线程还在运行,此时会产生新的对象) -并发标记预处理:希望减少下一个阶段重新标记的时间 将上一阶段并发脏的进行标为脏页 新生代可能又有老年代引用指向的对象(应minorGC来进行优化)
  • 重新标记 STW 扫描卡表,找出死的
  • 并发消除

优点和缺点

  • 优点:部分实现多线程
  • 缺点: 内存碎片太多,因为没有整理的算法,但是整理的算法会发生STW(纠结~)

G1

  • 引出了分区的概念,对分代的概念进行了弱化
  • 新生代和老年代的堆空间不再是确定的1:2,而是根据最大的停顿时间进行调整
  • G1解决跨代引用不是卡表,为RSET,其中的RSET在每个region都存在,记录着当前的region和其他region之间的引用对象的关系
  • G1的过程:分别为minor GC和mixed GC
minorGC的主要流程
  • 标记阶段:从GCROOT开始,标记活跃对象
  • 转移: 转移到新的region
  • 重定位:换个区域重新指向
mixedGC的主要流程
  • 标记阶段: 初始标记 并发标记 再标记
  • 清理 (无法解决转移过程中准确定位地址的问题)
  • 复制 涉及到GCROOT的一般会很慢

5、如何判断一个对象为垃圾

当没有印象指向他时,则为垃圾

判断方法

1、引用计数法

2、可达性分析法

啥样的引用可作为GCROOTs?
1、虚拟机栈中引用的对象
2、被static关键字修饰的 (static修饰的对象在JVM的整个生命周期中都存在)
3、synchronized同步锁所持有的对象

四、垃圾回收的过程

  • 所有的类都是在Eden区进行new创建的,当Eden用完后,使用minor GC(Young GC)进行回收。回收完剩余的复制进幸存者0区,当幸存者这0区满时候,进行赋值幸存者1区。再来时,进行GC回收,from和to区将会进行交换,谁空谁是to区
  • 当一个对象经历过15次minorGC还没被回收,年龄加1,扔进老年区老年区满时,则会执行FullGC,FULLGC则是将新生代和老年代一起进行回收
  • 若FULLGC后仍没有空间,则报OOM错
  • OOM的原因:Java虚拟机内存不够(内存指的都是堆内存),可通过调节-XMx(堆内存所占主机内存的比例)进行调整,或者是创建了一个大的对象不会进行回收(G1垃圾回收器)

五、引用的类型

  • 强引用
  • 弱引用 (在将要OOM时候进行回收)
  • 软引用 (在任何情况下都进行回收)
  • 虚引用 (擦屁股)

六、重要的一个问题

  • 跨代的问题,存在跨代引用,新生代的对象被老年代所引用,则不会被回收
  • 当新生代的对象要被回收时,需要遍历老年代,使用可达性分析法,去判断在老年代的引用是否还指向当前的对象,为了防止遍历老年代,引出记忆集
  • 记忆集将老年代划分为若干小块,标识出记忆集中哪一块存在跨代引用
  • 记忆集的实现方式为卡表(card table),记录非收集区域指向收集区域指针的集合
  • 原理:堆内存的每一块区域形成卡页,卡表是卡页的集合。当存在跨代引用的时候,将卡页标记为脏页,每次minorGC只需要从卡表中找到卡页,避免遍历访问老年代