现象

  • 所有的请求都卡住。
  • 堆dump正常。
  • 有一段时间内存占用高,GC频繁且耗时长,过了那段时间后监控上恢复正常。
  • 日志有OutOfMemory的异常

结论
在这段代码OOM之前,它会导致JVM不停 fullGC 与 stopWorld,从而导致了程序卡死。(这也是为什么那一天的上午日志中并没有OOM,但是请求却也被卡住)
在这段OOM之后,之前由于它的不停的挤占空间,而它每次又只申请一小块内存,因此导致一些申请稍大内存的地方提前爆出如上的OOM异常。因此即使最后的问题代码OOM了,所占用的内存被回收掉了,但是由于一些重要线程挂了,依然会导致请求无法被处理。

如果线程的异常没有被捕获,那么JVM会在线程终结前打印日志,该日志会打印到标准流(service_stdout)中去,如下(这么多重要线程都挂了)

为什么操作系统显示进程占用内存很多,但是堆dump却只有600M的大小
原因

连续大片内存,回收时,JVM会还给操作系统,通过brk移动指针就可以办到。(malloc如果要向操作系统申请内存时,将brk指针向上移动,free如果要向操作系统归还内存时,将brk向下移动,这意味着,它必须归还最上面的连续内存)
但是如果是很多的小的内存碎片,JVM不会还给操作系统,因为通过移动brk指针不能办到。

  • linux内核分页与Buddy:

    • https://www.cnblogs.com/theseventhson/p/15703182.html
  • linux内存分配(C语言与系统调用):
    • https://blog.csdn.net/TABE_/article/details/123098479
    • https://cloud.tencent.com/developer/article/1420726
  • JVM物理内存不释放:
    • https://cloud.tencent.com/developer/article/1912171

如下代码,发现以前占用的小内存JVM没有还给操作系统,即使已经被垃圾回收了:
操作系统显示一直保持这个值不变,但是GC日志显示已经回收了。


测试代码:

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;public class Main {public static volatile boolean shouldEnd = false;public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 2; i++) {new Thread(() -> {try {System.out.println("Loop Thread start");List<LocalDate> array = new ArrayList<>();while (!shouldEnd) {LocalDate localDate = LocalDate.now();array.add(localDate);}System.out.println("Loop Thread end");} catch (Throwable e) {System.out.println("Thread end");e.printStackTrace();}}).start();}while (true) {try {if (!shouldEnd) {Thread.sleep(10 * 1000);} else {Thread.sleep(1000);}byte[] arrays = new byte[512 * 1024 * 1024];System.out.println("Clock get big area!");} catch (Throwable e) {shouldEnd = true;e.printStackTrace();}}}
}

收获

  1. 不要死循环
  2. try catch 的时候尽量去catch Throwable,而不是Exception,这样即使OutOfMemeoy的时候,也能捕获到这个异常。当然像上面这个问题,即使去申请一个稍微大一点的数据,也可能导致自己的线程OOM,我们的代码不可能每一行都在 try catch 范围中。

一次简单的问题排查背后蕴含的巨大的知识量相关推荐

  1. 【摩客专访】简单易用的背后是吹毛求疵的追求 | 专访“方片收集”作者田飞

    采访者:做原型更快更简单的Mockplus 企划经理 Martin 受访者:"方片收集"作者田飞先生及其团队 本期"摩客专访"我们非常荣幸邀请到了"方 ...

  2. 简单探寻GCC编译器背后的故事

    目录 一.用gcc生成 .a静态库和 .so动态库 1.编辑生成例子程序 2.将hello.c编译成 .o文件 3.由 .o文件创建静态库 4.在程序中使用静态库 5.由.o 文件创建动态库文件 6. ...

  3. 《糖豆人:终极淘汰赛》成功背后蕴含了何种设计?

    「别推我!别抓我的尾巴,你们这群糖豆人滚啊!」 你在玩<糖豆人>时,嘴里十有八九会不由自主地说出这些话.数十个五彩缤纷的糖豆人相互推攘,紧抓对方肢体的景象已经席卷了整个游戏界. 自 8 月 ...

  4. 深富策略:罕见巨额成交量背后蕴含深意

    回顾周二A股行情,沪深两市小幅低开,盘初股指分化,随后沪指继续拉高,而深成指红盘上方窄幅整理.午后三大股指全线拉升,沪指走强中已经逼近年初高点,而深成指半年线附近迎来连续反弹,创业板指涨势稍弱.从盘面 ...

  5. 《数字中国建设整体布局规划》出炉,背后蕴含的数字城市巨大机遇

    近年来,数字经济的快速发展成为中国实现高质量发展的关键引擎.随着5G.云计算.人工智能等技术的飞速发展,数字经济正成为拉动中国经济增长的新动力.为了推动数字经济发展,日前发布<数字中国建设整体布 ...

  6. 音视频技术开发周刊 88期

    『音视频技术开发周刊』由LiveVideoStack团队出品,专注在音视频技术领域,纵览相关技术领域的干货和新闻投稿,每周一期.点击『阅读原文』,浏览第88期内容,祝您阅读愉快. 架构 思科:2022 ...

  7. hihocoder第226周:打表找规律

    题目列表 问题描述 有一个文本框,可以执行以下操作: 输入A Ctrl+C 复制 Ctrl+V 粘贴 Ctrl+A 全选 N次操作最多能够造出多少个A来? 输入一个N,输出一个整数,表示最多有多少个A ...

  8. 机器学习中的编码器-解码器结构哲学

    其它机器学习.深度学习算法的全面系统讲解可以阅读<机器学习-原理.算法与应用>,清华大学出版社,雷明著,由SIGAI公众号作者倾力打造. 书的购买链接 书的勘误,优化,源代码资源 本文PD ...

  9. cache 访问延迟背后的计算机原理

    简介:本文介绍如何测试多级 cache 的访存延迟,以及背后蕴含的计算机原理. CPU 的 cache 往往是分多级的金字塔模型,L1 最靠近 CPU,访问延迟最小,但 cache 的容量也最小.本文 ...

最新文章

  1. Python通过一个网页地址获得网页标题Title
  2. 推荐一位大佬,在腾讯工作十年
  3. 用 PS 调整服务器时间
  4. python docx 合并文档 图片_不再为处理PDF烦恼,python处理操作PDF全攻略
  5. Spring 拦截器和过滤器中自动注入为 null 的原因及解决方案
  6. c++如何禁用指定的键盘布局_Karabiner Elements for Mac 键盘键位自定义改键工具
  7. python 扫描仪_基于Opencv和Python的多选扫描仪
  8. 【Recat 应用】之 React 脚手架
  9. jquery click()方法模拟点击事件对a标签不生效的解决办法
  10. 选择数据分析工具应考虑4个因素
  11. CART树算法的剪枝算法
  12. Excel中插入图表后在设计选项卡无法选择样式解决办法
  13. openvpn部署和迁移
  14. 操作——【1.8 关于音高、时值、位置 】(二)
  15. 如何使用poi解析word生成html目录结构
  16. java FTP连接时出现“227 Entering Passive Mode”的解决方法
  17. strace命令用法详解
  18. 5.4 文本分析与加密
  19. oracle 数据字典画报,收藏!Oracle常用数据字典表、视图的总结,都在这里了
  20. 黑帽大会:黑客把入侵汽车当兴趣

热门文章

  1. python汽车招聘_【一点资讯】C/C++和Python在无人驾驶汽车招聘信息中位居热门技能冠亚! www.yidianzixun.com...
  2. scala语法 -多维数组
  3. 拔智齿过程的RAP现象
  4. 网络算法系列之社区发现(一):标签传播算法
  5. matlab实现拨号音识别
  6. 2014年5月最后一周工作总结
  7. 远鉴科技“语音识别”技术获美亚柏科青睐!
  8. 用PS制作256色的BMP图片
  9. L1X-2 矩阵转置 (10 分)
  10. Tarjan算法求割点与割边(python3实现)