java面试整理二——JVM_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > java面试整理二——JVM

java面试整理二——JVM

 2018/2/25 18:15:07  cpjsjxy  程序员俱乐部  我要评论(0)
  • 摘要:1.JVM的主要结构JVM主要由类加载子系统、运行时数据区、执行引擎以及本地方法接口组成。2.JVM的类加载机制a)加载i.通过一个类的全限定名来获取定义此类的二进制字节流ii.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构iii.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口b)验证c)准备:准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量
  • 标签:面试 Java面试 Java JVM
1. JVM的主要结构



JVM主要由类加载子系统、运行时数据区、执行引擎以及本地方法接口组成。
2. JVM的类加载机制



a) 加载
i. 通过一个类的全限定名来获取定义此类的二进制字节流
ii. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
iii. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
b) 验证
c) 准备:准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量)。注意,准备阶段只在内存中分配变量,初始值为零,变量赋值工作将在初始化时进行;但如果类变量被修饰为final时,初始值将被初始化
d) 解析
e) 初始化:根据程序员制定的计划对类变量及其他资源进行初始化操作
i. 加载类的实例
ii. 加载类的静态变量
iii. 加载类的静态方法
iv. 实例化一个对象
v. 初始化时先初始化父类
3. Java中的赋值顺序
a) 静态常量(static final)
i. 父类静态常量赋值
ii. 子类静态常量赋值
b) 静态变量和代码块(static)
i. 父类静态变量
ii. 父类代码块
iii. 子类静态变量
iv. 子类代码块
c) 父类的实例化变量赋值
d) 父类的构造实例化
e) 子类的实例化变量赋值
f) 子类的构造实例化
4. JVM的内存区域
a) 线程私有区域
i. 程序计数器
ii. Java Stack(虚拟机栈):java方法执行的内存模型,用于存储局部变量、操作数栈、动态链接、方法出口等信息
iii. 本地方法栈:为native方法服务
b) 线程共享区域
i. Heap(java堆)——存放各种对象实例
1. 新生代
a) Eden区、From survivor、To survivor
2. 老生代
ii. Method area(方法区)——我们通常说的永久带,用于存放类信息、常量、静态变量、编译后的代码等
5. 直接内存——不是JVM运行时数据区的一部分,但是也会被经常使用。JDK5以后引入的NIO提供了基于Channel和Buffer的IO方式,它可以使用native方式直接分配堆外内存,然后使用directByteBuffer对象作为这块内存的引用进行操作
6. GC对象的判定方法(对象存活的判定方法)
主要采用可达性算法(引用链法),从一个GC Roots的对象(虚拟机栈中引用的对象、方法区类静态属性引用的对象、方法区常量池引用的对象、本地方法栈引用的对象)开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则这个对象不可用。第一次是死缓,第二次立即执行。
7. Java的垃圾回收机制
在JVM中有一个负责垃圾回收的线程(优先级较低),当虚拟机空闲或者当前堆内存不足时,触发执行,扫描没有被任何引用的对象,放到回收的集合中进行回收
8. Java中垃圾回收的方法有哪些
a) 标记-清除——效率不高,产生内存碎片
b) 复制算法——新生代回收的核心算法。内存划分为8:1:1三部分,较大那份内存交Eden区,其余是两块较小的内存区叫Survior区。优先使用Eden区,如果Eden区已满,则将存活的对象复制到survior区,然后清除Eden区。如果survivor不够,则通过分配担保机制复制到老年代。
c) 标记-整理——解决标记清除算法的内存碎片问题。
d) 分带收集——现在的虚拟机大多采用这种方式进行垃圾回收。根据对象的生命周期,将堆分为新生代和老生代。新生代主要采用复制算法;老生代由于对象存活率较高,可以采用标记整理或标记清除算法。
9. Minor GC、Major GC和Full GC之间的区别
a) Minor GC是清理年轻代
b) Major GC是清理老年代,和full GC是一个意思。实际上full GC本身不会先进行Minor GC
c) 因为老年代很多对象都会引用到新生代的对象,先进行Minor GC可以提高老年代GC的速度
10. Java的垃圾回收器
a) Serial回收器——一个单线程回收器 -XX:+UseSerialGC
b) ParNew回收器——Serial的多线程版本,并行收集器,新生代并行,老年代串行;新生代复制算法,老年代标记压缩算法 -XX:+USeParNewGC
i. 停顿时间短、回收效率高、对吞吐量要求高
ii. 适用于大型应用、科学计算、大规模数据采集等
c) Parallel回收器——类似ParNew收集器,Parallel收集器更关注吞吐量。可以通过参数来打开自适应调节策略;也可以通过参数控制GC时间在毫秒级范围内;新生代赋值算法,老年代标记压缩算法。 -XX:+UseParallelGC
d) Parallel old回收器——Parallel scavenge回收器的老年代版本,使用多线程+标记整理算法。
-XX:+UseParallelOldGC
e) CMS(concurrent-mark-sweep)回收器——并发收集器是一种以获取最短回收停顿时间为目标的回收器。XX:+UseConcMarkSweepGC
i. 过程主要分为四步:
1. 初始标记(会stop)只是标记一下GC Roots能直接关联到的对象,速度很快
2. 并发标记
3. 重新标记(会stop)为了修正并发标记期间因用户程序继续运作而导致标记产生表动的那一部分对象的标记记录
4. 并发清除
ii. 优点:并发收集、低停顿【通过多线程执行扫描和回收,时间短的同时资源消耗相对高】
iii. 缺点:对CPU资源非常敏感、影响吞吐量、处理浮动垃圾会引起Full GC、产生内存碎片
f) G1回收器——一款面向服务器端应用的垃圾回收器。G1回收器将堆分为1M-32M的多个区域,并使用多线程在后台扫描他们。G1回收器会优先扫描包含垃圾较多的区域。-XX:UseG1GC
i. G1的运作步骤
1. 初始标记
2. 并发标记
3. 最终标记
4. 筛选回收
ii. 并行与并发——G1回收器能充分利用CPU资源在多核的优势下缩短stop时间
iii. 分代收集——能够采用不同的方式处理新创建的对象和已经存活一段时间的对象
iv. 空间整合——G1整体上采用标记—整理算法实现收集,局部上采用复制算法实现收集
v. 可预测停顿——建立可预测停顿时间的模型,能让使用者明确指定在一个毫秒级时间内
11. 并行与并发
a) 并发——一个处理器同时处理多个任务
b) 并行——多个处理器同时处理多个任务
12. JVM常用参数配置
a) -Xms:初始堆大小
b) -Xms:最大堆大小
c) -XX:NewSize=n:设置年轻代大小
d) -XX:NewRatio=n:设置年轻代和年老代的比值。如:为3表示年轻代和年老代比值为1:3 -XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如3表示Eden: 3 Survivor:2,一个Survivor区占整个年轻代的1/5
e) -XX:MaxPermSize=n:设置持久代大小
f) -XX:+UseSerialGC:设置串行收集器
g) -XX:+UseParallelGC:设置并行收集器
h) -XX:+UseParalledlOldGC:设置并行年老代收集器
i) -XX:+UseConcMarkSweepGC:设置并发收集器
j) -XX:UseG1GC:设置G1收集器
k) -XX:+PrintGC 输出GC日志
l) -XX:+PrintGCDetails 输出GC的详细日志
m) -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
n) -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
o) -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
p) -XX:+PrintGCApplicationStoppedTime // 输出GC造成应用暂停的时间
q) -Xloggc:../logs/gc.log 日志文件的输出路径并行收集器配置
13. 并行收集器配置
a) -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数
b) -XX:MaxGCPauseMillis=n:设置并行收集最大的暂停时间(如果到这个时间了,垃圾回收器依然没有回收完,也会停止回收)
c) -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为:1/(1+n)
d) -XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况
e) -XX:ParallelGCThreads=n:设置并发收集器年轻代手机方式为并行收集时,使用的CPU数。并行收集线程数
14. 什么情况下回产生Full GC
a) 老年代空间不足——老年代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出java.lang.OutOfMemoryError: Java heap space
b) 永生区空间不足——当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出java.lang.OutOfMemoryError: PermGen space
c) CMS GC时出现promotion failed和concurrent mode failure
i. promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入老年代,而此时老年代也放不下造成的;
ii. concurrent mode failure是在执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足造成的(有时候“空间不足”是CMS GC时当前的浮动垃圾过多导致暂时性的空间不足触发Full GC)。
15. 新生代GC和老生代GC
a) 新生代GC——串行GC(SerialGC)、并行回收GC(ParallelScavenge)和并行GC(ParNew)
b) 老生代GC——串行 GC(SerialMSC)、并行GC(parallelMSC)和并发GC(CMS)
c) 年轻代使用的CMS收集器也和并行收集器采用一样的算法
16. JVM优化思路
a) 年轻代大小的选择
i. 响应时间优先的应用:尽可能接近系统最低响应时间限制的条件下越大越好
ii. 吞吐量优先的应用:尽可能设置大,垃圾回收可以并行进行
b) 老年代大小的选择
i. 响应时间优先的应用:老年代使用并发收集器,所以其大小设置要小心
ii. 吞吐量优先的应用:一般都有一个较大的年轻代和一个较小的老年代
c) 较小堆引起的碎片问题
i. 如果老年代使用并发收集器(CMS),则需要开启老年代的压缩和配置多少次Full GC后对老年代进行压缩
d) 一般来说,稳定的堆大小对垃圾回收是有利的。获得一个稳定的堆大小的方法是使-Xms 和-Xmx 的大小一致,即最大堆和最小堆 (初始堆) 一样
e) 尝试使用大的内存分页 –XX:+LargePageSizeInBytes:设置大页的大小
这种机制,从数据结构上,保证了访问内存的高效,并使 OS 能支持非连续性的内存分配。
f) 吞吐量优先的方案将会尽可能减少系统执行垃圾回收的总时间,故可以考虑关注系统吞吐量的并行回收收集器。在拥有高性能的计算机上,进行吞吐量优先优化,可以使用参数:
java –Xmx3800m –Xms3800m –Xmn2G –Xss128k –XX:+UseParallelGC
   –XX:ParallelGC-Threads=20 –XX:+UseParallelOldGC
–Xmx3800m –Xms3800m:设置 Java 堆的最大值和初始值。
-Xss128k:减少线程栈的大小,这样可以使剩余的系统内存支持更多的线程;
-Xmn2g:设置年轻代区域大小为 2GB;
–XX:+UseParallelGC:年轻代使用并行垃圾回收收集器。可以尽可能地减少GC时间。
–XX:ParallelGC-Threads:设置用于垃圾回收的线程数,可以设置和 CPU 数量相等。
–XX:+UseParallelOldGC:设置年老代使用并行回收收集器。
g) 使用非占有的垃圾回收器
响应时间优先的应用,首先考虑的是使用关注系统停顿CMS 回收器;其次,为了减少 Full GC 次数,应尽可能将对象预留在年轻代,因为年轻代Minor GC的成本远远小于年老代的Full GC。
java –Xmx3550m –Xms3550m –Xmn2g –Xss128k –XX:ParallelGCThreads=20
–XX:+UseConcMarkSweepGC –XX:+UseParNewGC –XX:+SurvivorRatio=8 –XX:TargetSurvivorRatio=90
–XX:MaxTenuringThreshold=31

–XX:ParallelGCThreads=20:设置 20 个线程进行垃圾回收;
–XX:+UseParNewGC:年轻代使用并行回收器;
–XX:+UseConcMarkSweepGC:年老代使用 CMS 收集器降低停顿;
–XX:+SurvivorRatio:设置 Eden 区和 Survivor 区的比例为 8:1。稍大的Survivor空间可以提高在年轻代回收生命周期较短的对象的可能性,如果Survivor不够大,一些短命的对象可能直接进入年老代,这对系统来说是不利的。
–XX:TargetSurvivorRatio=90:设置 Survivor 区的可使用率。当存放的对象超过这个百分比,则对象会向年老代压缩。因此,这个选项更有助于将对象留在年轻代。
–XX:MaxTenuringThreshold:设置年轻对象晋升到年老代的年龄。默认值是15次,即对象经过15 次Minor GC依然存活,则进入年老代。这里设置31,目的是让对象尽可能地保存在年轻代区域。
17. 常用JVM回收策略
新生代 老年代 说明
Serial CMS+Serial Old CMS是并发GC,实现GC线程和应用线程并发工作,不需要暂停所有应用线程。另外,当CMS进行GC失败时,会自动使用Serial Old策略进行GC。
ParNew CMS 使用-XX:+UseParNewGC选项来开启。
ParNew是Serial的并行版本,可以指定GC线程数 -XX:ParallelGCThreads选项指定GC的线程数。
如果指定了选项-XX:+UseConcMarkSweepGC选项,则新生代默认使用ParNew GC策略
ParNew Serial Old 使用-XX:+UseParNewGC选项来开启。新生代使用ParNew GC策略,年老代默认使用Serial Old GC策略
Parallel Scavenge Parallel Old Parallel Scavenge策略主要是关注一个可控的吞吐量,适用于后台持久运行的应用程序,不适用于交互较多的应用程序
G1GC G1GC -server -XX:+PrintGC
-Xms10240m -Xmx10240m
-XX:PermSize=128m -XX:MaxPermSize=128m
-Xss256k
-Xloggc:${LOG_HOME}/logs/gc.log
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=HeapOOMError.log
-XX:+UnlockExperimentalVMOptions
-XX:+UseG1GC -XX:MaxGCPauseMillis=10
-XX:GCPauseIntervalMillis=200
-XX:+DisableExplicitGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
  • class='magplus' title='点击查看原始大小图片' />
  • 大小: 35.8 KB
  • 大小: 25.2 KB
  • 查看图片附件
发表评论
用户名: 匿名