面试过程中不免被问到 JVM 相关知识,总结了JVM一些经典面试题,分享出我自己的解题思路,希望对大家有帮助,有哪里你觉得不正确的话,欢迎指出,后续有空会更新。
想跳槽涨薪,面试怎么能少了他呢。
运行时数据区的定义:Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数 据区域。
根据 JVM规范,标准的JVM运⾏时数据区包括以下部分:
堆是 JVM 上最⼤的内存区域,我们申请的几乎所有的对象,都是在这里存储的。
以Hotspot为例,堆空间为了方便GC模块进行对象分配和回收,可以把堆空间进行以下划分:
内存溢出(OOM- Out Of Memory)是指JVM可用内存不足。
JVM运行需要使用的内存超出最大可用值,会导致JVM出现异常。 常见的OOM有以下几种。
内存泄漏(Memory Leak)是指本来无用的对象却继续占用内存,没有再恰当的时机释放占用的内存。 不使用的内存,却没有被释放,这个就叫做内存泄漏。
比较典型的场景是: 每一个请求进来,或者每一次操作处理,都分配了内存,却有一部分不能回收(或
未释放),那么随着处理的请求越来越多,内存泄漏也就越来越严重。
如果存在严重的内存泄漏问题,随着时间的推移,则必然会引起内存溢出。
内存泄漏一般是资源管理问题和程序BUG,内存溢出则是内存空间不足和内存泄漏的最终结果。
几种垃圾收集器:
需要根据系统的配置来确定,要给操作系统和JVM其他内存区域(栈、方法区)留下一定的剩余空间。 推荐配置系统或容器里可用内存的 70%~80%最好。
假设物理内存是8G,设置多大堆内存比较合适?
系统有 8G 物理内存,系统自己可能会用掉一点,大概还有 7.5G 可以用。
那么建议配置-Xmx6g (7.5g*0.8=6g)
因为GC过程中,所有应用线程都需要暂停之后才能执行GC,这时候就称为STW,或者叫做GC暂停。
用户线程暂停,GC线程要开始⼯作,但是要确保用户线程暂停的这行字节码指令是不会导致引用关系的 变化。所以JVM会在字节码指令中,选一些指令,作为“安全点”,比如方法调用、循环跳转、异常跳转 等,一般是这些指令才会产生安全点。
为什么它叫安全点,是这样的,GC时要暂停业务线程,并不是抢占式中断(立马把业务线程中断)而是 主动是中断。
主动式中断是设置一个标志,这个标志是中断标志,各业务线程在运⾏过程中会不停的主动去轮询这个 标志,一旦发现中断标志为True,就会在自己最近的“安全点”上主动中断挂起。
为什么需要安全区域? 要是业务线程都不执行(业务线程处于Sleep或者是Blocked状态),那么程序就没办法进入安全点,对于这种情况,就必须引入安全区域。
安全区域是指能够确保在某一段代码片段之中,引用关系不会发生变化,因此,在这个区域中任意地⽅ 开始垃圾收集都是安全的。我们也可以把安全区城看作被扩展拉伸了的安全点。
当用户线程执⾏到安全区域里面的代码时,首先会标识自己已经进入了安全区域,这段时间里JVM要发 起GC就不必去管这个线程了。 当线程要离开安全区域时,它要JVM是否已经完成了(根节点枚举,或者其他GC 中需要暂停用户线程 的阶段)
1、如果完成了,那线程就当作没事发生过,继续执行。
2、否则它就必须一直等待,直到收到可以离开安全区域的信号为止。
1、先通过top命令找到消耗cpu很高的进程id(假设是2732)
top 命令是我们在 Linux 下最常用的命令之一,它可以实时显示正在执⾏进程的 CPU 使用率、内存使用率以及系统负载等信息。其中上半部分显示的是系统的统计信息,下半部分显示的是进程的使用率统计信息
2、执行top -p 2732单独监控该进程
3、在第2步的监控界面输入H,获取当前进程下的所有线程信息
4、找到消耗cpu特别高的线程编号(假设是2734)
5、执⾏jstack 2732对当前的进程做dump,输出所有的线程信息
同时将第4步得到的线程十进制编号2734转成16进制(AAE),在堆栈信息里面去找对应线程内容
6、最后解读线程信息,定位具体代码位置
1.该对象没有与GC Roots相连
2.该对象没有重写finalize()方法或finalize()已经被执行过则直接回收(第一次标记)、否则将对象加入到F-Queue队列中(优先级很低的队列)在这里finalize()方法被执行,之后进行第二次标记,如果对象仍然应该被GC则GC,否则移除队列。 (在finalize方法中,对象很可能和其他 GC Roots中的某一个对象建立了关联,finalize方法只会被调用一次,且不推荐使用finalize方法)
方法区回收价值很低,主要回收废弃的常量和无用的类。
如何判断无用的类:
1.该类所有实例都被回收(Java堆中没有该类的对象)
2.加载该类的ClassLoader已经被回收
3.该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方利用反射访问该类
GC最基础的算法有三种: 标记 -清除算法、复制算法、标记-压缩算法,我们常用的垃圾回收器一般都采用分代收集算法。
摘录GC日志一部分(前部分为年轻代gc回收;后部分为full gc回收):
2016-07-05T10:43:18.093+0800: 25.395: [GC [PSYoungGen: 274931K->10738K(274944K)] 371093K->147186K(450048K), 0.0668480 secs] [Times: user=0.17 sys=0.08, real=0.07 secs]
2016-07-05T10:43:18.160+0800: 25.462: [Full GC [PSYoungGen: 10738K->0K(274944K)] [ParOldGen: 136447K->140379K(302592K)] 147186K->140379K(577536K) [PSPermGen: 85411K->85376K(171008K)], 0.6763541 secs] [Times: user=1.75 sys=0.02, real=0.68 secs]
通过上面日志分析得出,PSYoungGen、ParOldGen、PSPermGen属于Parallel收集器。其中PSYoungGen表示gc回收前后年轻代的内存变化;ParOldGen表示gc回收前后老年代的内存变化;PSPermGen表示gc回收前后永久区的内存变化。young gc 主要是针对年轻代进行内存回收比较频繁,耗时短;full gc 会对整个堆内存进行回城,耗时长,因此一般尽量减少full gc的次数。
Sun JDK监控和故障处理命令有jps jstat jmap jhat jstack jinfo
常用调优工具分为两类,jdk自带监控工具:jconsole和jvisualvm,第三方有:MAT(Memory Analyzer Tool)、GChisto。
新生代内存不够用时候发生MGC也叫YGC,JVM内存不够的时候发生FGC
-Xmx:堆内存最大限制。
-XX:NewSize:新生代大小
-XX:NewRatio 新生代和老生代占比
-XX:SurvivorRatio:伊甸园空间和幸存者空间的占比
祝大家工作顺利,升职加薪,面试都能通过,offer拿到手软,早日找到心仪的工作~
这份pdf已经给大家整理好,点开下面小卡片,扫码添加微信(备注:锦鲤)即可领取