《深入理解Java虚拟机》如何进行参数调优、垃圾回收算法
这一回以面试官与面试者的交流写~
先补充几个上一篇缺少的jvm参数
这块的参数是在启动的时候设置的,像上一章说的jinfo那些可以是在运行的时候查看的
-xmx 为jvm运行过程中分配的最大内存
-xms 为jvm启动时候分配的过程,也可以说是最小的~
-xmn 为新生代大小
-xss 为jvm启动的每个线程分配的内存大小
这几个其实挺好记住的,xss比较特殊,就是和每个线程有关。
xm中,x就是max 最大内存,s是small 最小或者说是启动时线程 ,n是new 就是新生代
-XX:NewRatio: 可以设置新生代与老年代的比例
-XX:SurvivorRatio:设置Eden区和survivor区的大小
上图中 Eden:from:to = 8:1:1 这个-XX:SurvivorRatio的值就是8
上图中 Old:new = 2:1 这个-XX:NewRatio的值就是2
jvm调优你是如何做的?
1、除了分析日志找出内存溢出
2、在容器里面使用linux内存使用情况查看:top、free等
3、使用jvm自带的命令,jmap +jhat 做dump文件分析
4、定位问题 可能是某个连接长时间没有释放、某个代码不合理进行重构、内存大小设置不合理
(后面介绍mysql慢查询排除也有这样的类似流程)
能举个例子吗?你遇到过的OOM的例子
1、线程池newFixedThreadPool和newSingleThreadExecutor方法他们都使用了LinkedBlockingQueue的任务队列。LikedBlockingQueue的默认大小为Integer.MAX_VALUE。而newCachedThreadPool中定义的线程池大小为Integer.MAX_VALUE。大量任务请求堆积,不断向队列添加任务就会导致内存溢出。
2、还有很多的情况,比如,老旧的项目从数据库连接池里面获取了连接,没有释放;从jedisPoo获取连接,没有释放。甚至有可能是,内存设置不合理,比如经历了一段时间的迭代,项目需要的内存越来越大,此时就要修改内存大小。
内存大小设置不合理?那你平时怎么设置内存大小的呢?
《Java性能优化权威指南》,记录了前人,多种调优之后得出的一个结论
Xmx 和 Xms设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍
永久代 PermSize和MaxPermSize设置为老年代存活对象的1.2-1.5倍。
老年代的内存大小设置为老年代存活对象的2-3倍。
简单记:FullGC之后的老年代内存占用的3倍,然后按照2:1分配老年代与新生代
当然这里有要结合不的业务场景,具体是做什么业务的,比如购物订单系统,一个订单多大平时有多少订单区推算。
你了解垃圾回收算法吗?垃圾回收算法有哪些?
1、标记-清除算法:属于最早的垃圾回收算法,它是由标记阶段和清除阶段构成的。标记阶段会给所有的存活对象做上标记,而清除阶段会把没有被标记的死亡对象进行回收。多用于老年代
2、标记-整理算法:标记阶段和整理阶段。其中标记阶段和标记-清除算法的标记阶段一样,不同的是后面的一个阶段,标记-整理算法的后一个阶段不是直接对内存进行清除,而是把所有存活的对象移动到内存的一端,然后把另一端的所有死亡对象全部清除。多用于老年代;相对于标记清除算法,标记整理算法更消耗性能,所以现代的堆内存回收,一般是“标记-清除算法”与“标记-整理算法”同时使用,可以是3次“标记-清除算法”后,进行一次“标记-整理算法”。
3、复制算法:这个算法多用于新生代,为什么呢?新生代对象的创建与清理比较频繁,上面两个算法用起来最少都要扫描两次,我们就以牺牲一半内存的方法,做出了复制算法。