Java面试题-jvm7垃圾收集器 Java面试题-jvm3 Java面试题-jvm1 Java面试题-jvm2 Java面试题-jvm5 Java面试题-jvm4 Java面试题-jvm6
你会估算GC频率吗?
正常情况我们应该根据我们的系统来进行一个内存的估算,这个我们可以在测试环境进行测试,最开始可以将内存设置的大一些,比如4G这样,当然这也可以根据业务系统估算来的。
比如从数据库获取一条数据占用128个字节,需要获取1000条数据,那么一次读取到内存的大小就是((128 B/1024 Kb/1024M)* 1000 = 0.122M,那么我们程序可能需要并发读取,比如每秒读取100次,那么内存占用就是0.122100 = 12.2M,如果堆内存设置1个G,那么年轻代大小大约就是333M,那么333M*80%/12.2M =21.84s,也就是说我们的程序几乎每分钟进行两到三次youngGC。这样可以让我们对系统有一个大致的估算。
内存优化
- 内存分配
正常情况下不需要设置,那如果是促销或者秒杀的场景呢?
每台机器配置2c4G,以每秒3000笔订单为例,整个过程持续60秒
- 内存溢出(OOM)
一般会有两个原因:
(1)大并发情况下
(2)内存泄露导致内存溢出
- 大并发[秒杀]
- 浏览器缓存、本地缓存、验证码
- CDN静态资源服务器
- 集群+负载均衡
- 动静态资源分离、限流[基于令牌桶、漏桶算法]
- 应用级别缓存、接口防刷限流、队列、Tomcat性能优化
- 异步消息中间件
- Redis热点数据对象缓存
- 分布式锁、数据库锁
- 5分钟之内没有支付,取消订单、恢复库存等
- 内存泄露导致内存溢出
ThreadLocal引起的内存泄露,最终导致内存溢出
public class TLController {
@RequestMapping(value = "/tl")
public String tl(HttpServletRequest request) {
ThreadLocal<Byte[]> tl = new ThreadLocal<Byte[]>();
// 1MB
tl.set(new Byte[1024*1024]);
return "ok";
}
}
(1)上传到服务器
jvm-case-0.0.1-SNAPSHOT.jar
(2)启动
java -jar -Xms1000M -Xmx1000M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=jvm.hprof jvm-case-0.0.1-SNAPSHOT.jar
(3)使用jmeter模拟10000次并发
(4)top命令查看
top
top -Hp PID
(5)jstack查看线程情况,发现没有死锁或者IO阻塞的情况
jstack PID
java -jar arthas.jar ---> thread
(6)查看堆内存的使用,发现堆内存的使用率已经高达88.95%
jmap -heap PID
java -jar arthas.jar ---> dashboard
(7)此时可以大体判断出来,发生了内存泄露从而导致的内存溢出,那怎么排查呢?
jmap -histo:live PID | more
获取到jvm.hprof文件,上传到指定的工具分析,比如heaphero.io