Java面试题系列——JavaSE面试题(JVM二)

1、设置新生代与老年代优化参数?

1.-XX:NewRatio=2 表示新生代占1,老年代占2。则新生代占整个堆的1/3。可以修改-XX:NewRatio=4,表示新生代占1,老年代占4,新生代占整个堆的1/5,默认情况下,新生代和老年代的比例是1:2。(这个参数一般不会使用)
2.在HotSpot中,Oracle JVM官网说Eden区和另外两个Survivor空间默认所占的比例是8:1:1。如果需要设置的话,自己直接设置-XX:SurvivorRatio就可以了。
3. -XX:-UseAdaptiveSizePolicy :关闭自适应的内存分配策略 
4.-Xmn:设置新生代的空间的大小。 

5. 几乎所有的对象都在Eden区别new出来。
 

总结:不同的堆分布情况,对系统执行会产生一定的影响,在实际工作中,应该根据系统的特点做出合理的配置,基本策略:尽可能将对象预留在新生代,减少老年代的GC次数。除了可以设置新生代的绝对大小(-Xmn),可以使用(-XX:NewRatio)设置新生代和老年代的比例:-XX:NewRatio=老年代/新生代。

新生代老年代示意图:

2、内存泄漏与内存溢出的区别?

(1)内存溢出(Out Of Memory)

内存溢出(Out Of Memory):是程序在申请内存时,没有足够的内存空间供其使用。比如:你需要10M的空间,内存空间只剩8M,这就会出现内存溢出。

(2)内存泄漏  (Memory Leak)

内存泄漏  (Memory Leak):是程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重。memory leak最终会导致out of memory。这块内存不释放,就不能再用了,就叫这块内存泄漏了。

以发生的方式来分类,内存泄漏可以分为4类: 
1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。 
2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。 
3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。 
4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。
真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较常发性和偶发性内存泄漏它更难被检测到。

内存溢出的原因及解决方案:(1)修改JVM启动参数,直接增加内存。(2)检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。(3)对代码进行走查和分析,找出可能发生内存溢出的位置。(4)使用内存查看工具动态查看内存使用情况。

出现内存溢出和内存泄露,重点排查几点:

1、检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条以上记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询,查多少字段用多少字段。
2、检查代码中是否有死循环或递归调用。
3、检查是否有大循环重复产生新对象实体。
4、检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。使用list.clear()或者map.clear()
 

3、内存溢出你是咋解决的?

错误提示: java.lang.OutOfMemoryError: Java heap space

解决办法:设置堆内存大小 -Xms1m -Xmx70m -XX:+HeapDumpOnOutOfMemoryError

4、栈溢出你是咋解决的?

错误原因: java.lang.StackOverflowError
栈溢出 产生于递归调用,循环遍历是不会的,但是循环方法里面产生递归调用, 也会发生栈溢出。 解决办法:设置线程最大调用深度,利用-Xss5m 设置最大调用深度。

5、JVM参数调优的总结

在JVM启动参数中,可以设置跟内存、垃圾回收相关的一些参数设置,默认情况不做任何设置JVM会工作的很好,但对一些配置很好的Server和具体的应用必须仔细调优才能获得最佳性能。通过设置我们希望达到一些目标:1、GC的时间足够的小。2、GC的次数足够的少3、发生Full GC的周期足够的长。但是前两个目前是相悖的,要想GC时间小必须要一个更小的堆,要保证GC次数足够少,必须保证一个更大的堆,我们只能取其平衡。

(1)针对JVM堆的设置,一般可以通过-Xms -Xmx限定其最小、最大值,为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,我们通常把最大、最小设置为相同的值(2)年轻代和年老代将根据默认的比例(1:2)分配堆内存,可以通过调整二者之间的比率NewRadio来调整二者之间的大小,也可以针对回收代,比如年轻代,通过 -XX:newSize -XX:MaxNewSize来设置其绝对大小。同样,为了防止年轻代的堆收缩,我们通常会把-XX:newSize -XX:MaxNewSize设置为同样大小
(3)年轻代和年老代设置多大才算合理?毫无疑问是没有答案的,否则也就不会有调优。我们观察一下二者大小变化有哪些影响

1、更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC

2、更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率

3、如何选择应该依赖应用程序对象生命周期的分布情况:如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性,在抉择时应该根据以下两点:(A)本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理 (B)通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1。但应该给年老代至少预留1/3的增长空间。

持续更新中,敬请期待!

参考文章:

java 虚拟机(jvm)基本概念和虚拟机参数配置 - 简书

java虚拟机概念以及各参数的配置 - 爱码网

JVM系列之七:HotSpot 虚拟机 - 走看看

内存泄漏和内存溢出有啥区别? - 知乎

30.堆区中新生代和老年代相关参数设置(-XX:NewRatio和-XX:SurvivorRatio)_simpleGq的博客-CSDN博客_newratio默认值

内存溢出和内存泄漏的区别及详解_傻鱼爱编程的博客-CSDN博客_内存泄漏和内存溢出有什么区别

新生代与老年代中相关参数的设置 - 简书

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小海海不怕困难

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值