小伙伴问题:Java堆内存用到100%了,咋办呀?该从哪里下手排查?
聊聊:堆内存设置的主要参数?
-Xms
:初始堆大小(默认:物理内存的1/64)
-Xmx
:最大堆大小(默认:物理内存的1/4)
-Xmn
:新生代大小
-XX:SurvivorRatio
:设置eden/form/ro的比例 (默认:8:1:1)
-XX:NewRatio
:设置老年代/新生代的比例(默认:2)
-XX:+PrintGC/-XX:+PrintGCDetails
:打印 GC 的过程信息
-XX:MaxTenuringThreshold
:设置年轻代超过多少要进入老年代(默认:15)
聊聊:JVM运行的常用管理工具
jps
:查看当前系统运行的Java进程(进程号+名字;-m进程参数;-l程序的全路径;-v:传递给Java的main函数的函数参数)jstat
:查看堆信息jinfo
:查看虚拟机参数(也可以修改某些参数)jstack
:查看线程的堆栈信息(查看线程拥有的锁,分析死锁的原因)jstatd
:查看远程的Java进程jcmd
:jdk7新增;可以查看Java进程,导出进程信息,执行GC等操作。
聊聊:JVM可视化管理工具(jdk自带的)有哪些?
jconsole(jconsole)
jvisualvm(visual VM)
jmc(Mission Control)
查看堆内存,线程,加载类,cpu,dump等信息,检查死锁,内存溢出的原因
聊聊:哪些对象会被存放到老年代?
新生代对象每次经历⼀次minor gc,年龄会加1,当达到年龄阈值(默认为15岁)会直接进⼊老年代;
大对象直接进⼊老年代;
新生代复制算法需要⼀个survivor区进行轮换备份,如果出现大量对象在minor gc后仍然存活的情况时,就需要老年代进行分配担保,让survivor⽆法容纳的对象直接进⼊老年代;
如果在Survivor空间中相同年龄所有对象大⼩的总和大于Survivor空间的⼀半,年龄大于或等于该年龄的对象就可以直接进⼊年⽼代。
聊聊:什么时候触发full gc?
调用System.gc时,系统建议执行Full GC,但是不必然执行
老年代空间不⾜
方法区空间不⾜
通过Minor GC后进入老年代的平均大小大于老年代的可用内存
由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小
聊聊:七个垃圾回收器之间如何搭配使用
Serial New
收集器是针对新生代的收集器,采用的是复制算法;Parallel New
(并行)收集器,新生代采用复制算法,老年代采用标记整理;Parallel Scavenge
(并行)收集器,针对新生代,采用复制收集算法;Serial Old
(串行)收集器,新生代采用复制,老年代采用标记清理;Parallel Old
(并行)收集器,针对老年代,标记整理;CMS
收集器,基于标记清理;G1
收集器(JDK):“标记-复制”和“标记-整理”。从整体上看是基于“标记-整理”,从局部看,两个region之间是“标记-复制”。;综上:新生代基本采用复制算法,老年代采用标记整理算法。
聊聊:有没有JVM调优经验?JVM调优方案有哪些?
调优时机:
a. heap 内存(老年代)持续上涨,达到设置的最大内存值;
b. Full GC 次数频繁;
c. GC 停顿时间过长(超过1秒);
d. 应用出现OutOfMemory 等内存异常;
e. 应用中有使用本地缓存,且占用大量内存空间;
f. 系统吞吐量与响应性能不高或下降。
调优原则:
a. 多数的Java应用不需要在服务器上进行JVM优化;
b. 多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题;
c. 在应用上线之前,先考虑将机器的JVM参数设置到最优(最适合);
d. 减少创建对象的数量;
e. 减少使用全局变量和大对象;
f. JVM优化,是到最后不得已才采用的⼿段;
g. 在实际使用中,分析GC情况优化代码比优化JVM参数更好;
调优目标:
a. GC低停顿;
b. GC低频率;
c. 低内存占用;
d. 高吞吐量;
调优步骤:
a. 分析GC日志及dump⽂件,判断是否需要优化,确定瓶颈问题点;
b. 确定jvm调优量化目标;
c. 确定jvm调优参数(根据历史jvm参数来调整);
d. 调优⼀台服务器,对比观察调优前后的差异;
e. 不断的分析和调整,知道找到合适的jvm参数配置;
f. 找到最合适的参数,将这些参数应用到所有服务器,并进行后续跟踪。
聊聊:你们项目如何排查JVM问题的?
对于还在正常运行的系统:
可以使用jmap来查看JVM中各个区域的使用情况
可以通过jstack来查看线程的运行情况,比如哪些线程阻塞、 是否出现了死锁
可以通过jstat命令来查看垃圾回收的情况,特别是fullgc,如果发现fullgc比较频繁,那么就得进行调优了
通过各个命令的结果,或者jvisualvm等⼯具来进行分析
首先,初步猜测频繁发送fullgc的原因,如果频繁发⽣fullgc但是⼜⼀直没有出现内存溢出,那么表示 fullgc实际上是回收了很多对象了,所以这些对象最好能在younggc过程中就直接回收掉,避免这些对象进⼊到老年代,对于这种情况,就要考虑这些存活时间不⻓的对象是不是比较大,导致年轻代放不下,直接进⼊到了老年代,尝试加大年轻代的大⼩,如果改完之后,fullgc减少,则证明修改有效
同时,还可以找到占用CPU最多的线程,定位到具体的方法,优化这个方法的执行,看是否能避免某些对象的创建,从而节省内存
对于已经发⽣了OOM的系统:
⼀般⽣产系统中都会设置当系统发⽣了OOM时,⽣成当时的dump⽂件(- XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/base) 我们可以利用jsisualvm等⼯具来分析dump⽂件 根据dump⽂件找到异常的实例对象,和异常的线程(占用CPU⾼),定位到具体的代码 然后再进行详细的分析和调试
总之,调优不是⼀蹴而就的,需要分析、 推理、 实践、 总结、 再分析,最终定位到具体的问题
聊聊:如何查看线程死锁?
可以通过jstack命令来进行查看,jstack命令中会显示发⽣了死锁的线程
或者两个线程去操作数据库时,数据库发⽣了死锁,这是可以查询数据库的死锁情况
1、 查询是否锁表
show OPEN TABLES where In_use > 0;
2、 查询进程
show processlist;
3、 查看正在锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
4、 查看等待锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
硬核面试题推荐
核心面试题目:什么是索引下推?什么是 MRR 优化?怎么才能更好的为表创建索引? 核心面试题目:什么是 回表查询、索引覆盖、最左匹配原则?说说聚集索引、非聚集索引的区别?
面试重点难题:Mysql如何实现RR级隔离时,不会幻读? 核心面试题:请说说 HashMap 的时间复杂度是多少? 核心面试题: 强引用、软引用、弱引用、虚引用?重点是 各自的 使用场景? 吊打面试官:Java中String对象的大小? 核心面试难题:Java对象为什么 不一定在堆上分配? 核心面试题:MVCC、间隙锁、Undo Log链、表级锁、行级锁、页级锁、共享锁、排它锁、记录锁等等 核心面试题:为什么新生代要两个Survivor区? 一个不行吗? 核心面试题:用过分布式锁吗?你们是怎么做选型的?
硬核文章推荐
一文搞懂:Java高手必备之 Mpsc 无锁队列 (史上最全) 一文搞懂:微服务核心组件 Nacos(史上最全) 一文搞懂:微服务核心组件 sentinel(史上最全) 一文秒懂:多级时间轮,最顶尖的Java调度算法 一文搞懂:缓存之王 Caffeine 架构、源码、原理(5W长文) 高性能组件:环形队列、 条带环形队列 Striped-RingBuffer 架构分析 一文穿透:队列之王 Disruptor 原理、架构、源码 如何优雅的使用 单例模式 ?来看看缓存之王 Caffeine 、链路之王 Skywalking 是如何做的吧! 细思极恐:Java官方JVM 为啥要叫做 HotSpot JVM?背后的水,不知道有多深!!! Java核心实操:内存溢出 实战、内存泄漏实战
硬核电子书
本文收录于:《尼恩Java 面试宝典》V19版
长按二维码,点击“识别图中二维码”即可查看老架构师尼恩个人微信,发暗号 “领电子书” 给尼恩,获取最新PDF。
最新的《尼恩Java面试宝典》
极致经典,不断升级,目前最新为V19
尼恩Java高并发三部曲
《Java高并发核心编程-卷1(加强版)》,不断升级
《Java高并发核心编程-卷2(加强版)》,不断升级
《Java高并发核心编程-卷3(加强版)》,不断升级
尼恩架构笔记100篇+,不断添加