Products
GG网络技术分享 2026-01-21 01:52 2
说实话, 写代码这行当,有时候真让人头秃。特bie是当你辛辛苦苦上线了一个Spring Boot应用, 本来想着周五晚上Neng去撸个串喝点啤酒,后来啊运维半夜打 这时候你怎么办?重启服务?那是治标不治本,过两天还得炸。真正的勇士,敢于直面惨淡的日志,敢于正视淋漓的鲜血——咱们得去kanGC日志!没错,就是那些kan起来像天书一样的字符流。今天我就结合我Zui近踩过的一个大坑,跟大家唠唠怎么tong过这玩意儿排查springboot 内存泄漏。虽然过程hen痛苦,但这就像拔牙一样,拔完虽然疼两天但以后就不疼了嘛。 那个让人崩溃的下午:几十兆文件引发的血案 事情是这样的, 那天下午我正盯着屏幕发呆呢,突然监控系统就开始狂叫。我们的应用响应时间直接飙升到几万毫秒,CPU也是忽高忽低跟坐过山车似的。背景:一次性将几十兆几百兆的文件读到内存里,ran后再传给用户,服务器就爆了。 后来我去查代码,差点没背过气去。有个哥们为了图省事,直接把一个大文件读到一个byte数组里了!我就想问,兄弟你脑子瓦特了吗?几百万个对象瞬间在堆里创建出来那是什么概念?那简直就是春运期间的火车站啊!解决原则:读一点传一点。这句老话说了八百遍了怎么就是不听呢?解决方法:利用流,循环读写这才是正道啊!我们后来改成了使用HttpURLConnection和bufferedInputStream缓存流的方式来获取下载文件,读取InputStream输入流时,每次读取的大小为5M,不一次性读...进内存里。改完之后世界瞬间清静了,动手。。 概述如guo在大学里学过huo者在工作中使用过 C huo者 C++ 的读者一定会发现这两门语言的内存管理机制与 Java 的不同。在使用 C huo者 C++ 编程时,程序员需要手动的去管理和维护内存,就是说需要手动的... Java虽然自动回收dan是不代表你可yi随便造啊! 工欲善其事必先利其器:先把监控给我开起来! 别等到死透了才想起来kan病药方dou没开呢!设置JVM参数:tong过设置JVM参数,如-XX:+HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath,在发生内存溢出时生成堆转储文件,便于后续分析。这一步jue对是保命符!我以前吃过亏没设这个参数后来啊重启之后啥dou没了只Neng干瞪眼。 监控和:tong过监控应用的内存使用情况和查kan相关日志,及时发现内存泄漏的迹象也hen重要。Sring Boot 应用时启用 JMX 远程监控:上述参数开放 JMX 端口 9010,便于 VisualVM 连接本地或远程 JVM 实例你知道吗?kan着那个波浪线一直往上窜心里真的是慌得一比。tong过 VisualVM 你Nengkan到实时的堆内存走势如guo每次Full GC之后那个水位线dou不降反而升那就完蛋了百分之百是漏了没跑了! 工具名称 主要用途 适用场景 上手难度 JConsole JDK自带的基本监控 临时查kan一下CPU和线程概览 简单得不Neng再简单 JVisualVM JDK自带的分析神器 CPU抽样、简单的堆Dump预览 中等吧kan你是否习惯界面操作 Eclipse MAT MAT是专业的! Dominator Tree分析大对象 Retained Size计算 泄漏嫌疑点报告 这玩意儿必须掌握! 有点难上手dan是学会了就是神器 jstat/jmap命令行 B格高纯文本输出适合装老鸟 CIDC环境没有图形界面的时候只Neng靠它了 还可yi导出dump文件 jmap -dump:format=b,file=heap.hprof 背命令hen烦人建议记小抄! Groovy Console Btrace追踪栈动态注入代码不需要重启! btrace追踪栈ran后查kan使用MCC的地方发现没有配置扫包路径默认是扫描suo有的包_ java 堆外内存泄漏排查 深入虎穴:解读GC日志里的秘密代码 GC事件类型 发生区域 特征描述 心情指数 Minor GC / Young GC Eden区 或 Survivor区 心情平静甚至有点小开心说明系统活跃. Mixed GC Eeden + 部分 Old GenG1收集器特有的 效率还不错 如guo频繁出现可Neng需要调优Region大小.稍微有点紧张关注一下频率.CMS Concurrent Mark Sweep/td Ole Gen 收集器主打低延迟 dan是会产生碎片如guo碎片太多就会退化为 Serial Old 这个时候就慢死了!/td 心情烦躁 CPU飙升 用户投诉./span/tr Ful GC /td 整个堆 Eden/Survivor/Old Gen quan部清理 Stop The World 时间Zui长 kan到这个就要警惕了如guo是偶发还好要是频繁出现那就是事故前奏!/td/span/tr/tbody/table 这玩意儿用不好简直就是定时炸弹 ThreadLocal 的 key 是弱引用dan是 value 是强引用 如guo线程池里的线程一直不销毁 线程又拿着 ThreadLocal 的引用 那 value 不就一直释放不了吗? 这就像你借了图书馆的书 书过期了 你把借书卡扔了 dan是书还在你书包里 图书馆以为书丢了 其实还在! 这种情况下一定要记得用完 remove 掉! 我们用了某个第三方库 后来啊发现 Resin huo者 Tomcat 甚至 JVM 层面的物理内存在不断上涨 dan是 Java Heap 却hen正常! 这时候你kan不到 Java 对象的增长 只有 top 命令Nengkan到进程 RES 越来越高! 后来查出来是 DirectByteBuffer huo者 native 内存没释放! 这种问题Zui难搞 只Neng用 jcmd VM.native_memory summary detail huo者 google-perftools 来kan了! glibc 为了性Neng并不会立刻把物理内存在 malloc free 后还给操作系统而是留下来放入内存池导致应用层以为发生了 泄漏! suo以修改 MCC 的配置路径为特定的 JAR 包 问题解决!) 真的被 Linux 这种机制坑惨了 明明释放了它就是不还给你! 本文探讨了一个在 Docker 容器中运行的 SpringBoot Java 应用遇到的内存问题 特bie是 内存泄漏 tong过分析和故障排除 发现问题源于 Spring Boot 默认的200个线程池大小 降低线程池大小至16个线程后 成功解决了 内存泄漏 问题 文章还介绍了使用 Datadog jemalloc 和 jeprof 等工具进行内存问题诊断的方法 学习 C 知道 消息历史深入 Springboot 内存泄露问题排查 版权本文探讨了一个在 Docker 容器中运行的 SpringBoot Java 应用遇到的内存问题 特bie是 内存泄漏 tong过分析和故障排除 发现问题源于 Spring Boot 默认的200个线程池大小 降低线程池大小至16个线程...),踩个点。
Demand feedback