Java 应用内存不断增长
启动参数如下
java -server -Xms2048m -Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/xxx/heapError -jar xxx.jar --spring.profiles.active=prod --server.port=9551
项目启动一周后内存就已经 2.6g 了。。。也没有出现过 oom 异常,请教大家应该如何排查解决呢?
jdk版本如下
java version "1.8.0_361"
Java(TM) SE Runtime Environment (build 1.8.0_361-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.361-b09, mixed mode)
堆 dump 看看
dump 下来去分析内存
找算命先生测算一下
超出堆内存大小,应该就是堆外内存的问题了。用上面兄弟的 jmap dump 出来看看。但要注意会触发 FGC 。
xmx 限制了,那就是堆外泄露了呗
没挂能跑就行,管它呢。配置的 Xmx 只是堆内存大小,jvm 自己使用的内存,文件句柄啊,线程本身内存啊的都不在这里。
蹲一下解决方案,我有个开发的应用也是这样,时间越长内存越高,慢慢稳定在约束的最大内存,永远不会自动是释放内存,推测是写代码习惯问题,导致对象得不到释放
arthas 在线看一下内存占用情况
我们公司现在使用 消息中间件 nats 也有这种问题 😅
管他呢,搞个定时重启完事
查查有没有静态的集合,一般这种稳定增长的就是静态 map 或者 list 越来越大。不过我也建议写个定时重启算了。
这个得看你的项目有多大,小项目内存持续增大,大概率是代码问题,没有及时释放内存,需要看 dump
巧了,我写的其中一个 netty 也是这样,后来实在找不到问题了,每两个月重启一下
每天重启下就好了,java 就这样的
巧了,我写的其中一个 netty 也是这样,后来实在找不到问题了,每两个月重启一下Netty 大量使用了堆外内存。
hprof
启动参数加上-XX:NativeMemoryTracking=summary ,然后 jcmd pid VM.native_memory 分析下
巧了, 我也遇到过这个问题, 不过增长的慢, 离职了都没想着去解决这个问题. 蹲下排查方法
别理解错了,xmx 只限制了堆的最大值,还有非堆,线程栈,代码缓存,jvm 本身运行所需要的内存等,如有必要可以配置 NMT 进行分析,但是注意有性能损耗
mark 等个大佬,公司项目也是,看 arms 堆内存+非堆不到占用的内存,怀疑堆外又没办法排查,最后只能重启
netty 这种应用内存就是跟着连接数涨的,吃的是堆外内存,一条连接一个读写缓冲区。gc 管不着
巧了,我们把网关升级到 spring gateway 之后,也出现这问题,就是 netty 申请的堆外内存导致的。
2.6G 内存,超过堆内存的上限 2G ,堆外内存泄漏了。先 smaps 看下堆内存占用多少,算出堆外内存占用。堆外内存如果没特殊配置,最大也只能占 2G ,可能很快就 OOM 了。堆外内存很难定位泄漏点,给一个参考: tech.meituan.com/2018/10/18/netty-direct-memory-screening.html实在不行只能把内存用 gdb dump 出来,然后强行查看里面的内容,推测可能的泄漏原因。
#23 你说的这个,又是 smaps ,又是 gdb ,大部分的 java 开发不懂
不是人均阿里 P7 P8 水平,大部分还是 CRUD
#24 不过还是可以学到知识
哈哈哈 我的是内存正常 但是十几天后占用内存变小 随后宕机 问题是内存泄露 高并发的读取数据库导致有些线程超时未能关掉 好烦 不多线程的话 方法执行完需要三分多钟 现在还没想到长期运行的办法
#24 想问下排查内存泄漏这种问题对于 Java 开发是什么层次。曾经解决过公司一个服务的内存泄漏,堆外问题确实很难定位到,从简单的 NativeMemoryTracking ,pmap 查看内存分配,监控栈函数调用,jeprof 对比堆内分配,最终定位到框架的问题,确实在对应版本 issue 中找到,升级后解决。
- JVM 不是它需要多少内存,才占用多少内存;而是在 -Xmx 允许的前提下,只要你系统还有空余,它就会大方地申请占用;而且即使之前申请了,后续不需要这么多了,它也不会及时退还给 OS ; 你可以通过 jhsdb jmap --heap --pid ${jvm_pid} 来确认你的应用当前实际只 需要/占用 多少内存; 如果你希望让 JVM 需要多少内存,才占用多少内存,多占用了就及时释放,可以通过调整 -XX:MinHeapFreeRatio -XX:MaxHeapFreeRatio 来实现。
当然上面所说,前提是你的应用没有内存泄漏。
#24 对于一些非重要服务,楼上的低频时段重启确实简单暴力,排查内存泄漏问题起码两周起步
#28 P7 P8 我说的可能有点夸张了,但实际中大部分 Java 开发不会(不想浪费时间或者没有能力)这么排查,大部分就是扩容服务器、容器内存+定期重启解决
学到了
-Xms -Xmx 限制的是堆内存,JVM 不止有堆内存,JVM 内存大于 Xmx 是正常情况。堆内存只是用来存储对象的成员变量的,对象的方法运行期间使用的基本类型变量(包括数组),要占用栈内存,这些是随运行动态申请和释放的。如果是服务器负荷期间内存升高,无需理会,负荷降了就会自己下去。Java 类定义,类的成员方法的函数定义,类的静态变量,也是要占用内存的。这些内存通常是一旦加载就不会释放(具体取决于类加载器),这种情况会导致 JVM 启动一段时间后内存就略微增长。但这种情况也请无需理会,首先这是 JVM 的职责,其次就算它真是屎山你也不该去碰。
#32 我没有大厂经验,想了解下现在的行情。年后要重新找工作(允悲
堆外内存设置 JVM 管不着,项目迭代快就懒得管了(基本一两周就会上线一次),没崩就行
换 openj9
看内存快照,里面看下 dominator_tree 最大对象是不是有啥问题
很好奇,都说堆外内存泄露的,难不成都是用 jni 开发 Java 项目嘛?
你的 jdk 版本号多少,我遇到过 java8 低版本 bug ,会导致堆外内存一直涨
哥们,线程不占内存?
-XMX 定好了,那大概率是堆外,不确定你这是 RSS ,还是 COMMITED 的 2.6G ,建议开 NMT 然后看一下假如没有 native memory leak ,大概率是有线程泄漏了,导致内存泄漏了
#28 层次是和别人对比出来的例如你觉得自己底层厉害,想找基础框架的,那么和基础框架组的人对比,你的能力是什么范围,懂底层的多少东西,如果只会内存泄漏这一个,其他的不熟悉,那你定级就比较低。假如你 JVM 精通、线程模型精通、数据结构精通,网络精通,那又是另一个层面。排查问题是一种能力,根据知识来设计软件架构又是一种能力
我觉得你说的有道理。xmx 确实只限制堆内存。内存的问题就应该交给 JVM 处理。再怎么调优都比不过新的 jdk 带的垃圾收集器优先排查代码问题,再考虑 JVM 调优知乎的这篇文章可能对 OP 有帮助 zhuanlan.zhihu.com/p/432258798
#43 OK 了解,多谢回复,学习成长路漫漫。(后面几个精通给我干懵了
2.6G 如果不出现内存报警,要么你的 2.6G 不准,要么有堆外内存(比如 netty 可以创建堆外内存),同时也建议看看 gc 次数频繁不频繁你也说了是一周之后 2.6G,但是这个并没有什么参考,你需要看这一周的内存变化,来分析情况
起个定时任务强制 full gc ,都不用重启了/dog
先升级 jdk 版本看看
多对比几次 smaps 看堆外内存有没有持续上涨
笑死了,当初我们开发的一个项目,根据模板渲染 Excel 表格,里面的图片很多(五六十张吧),最后转成 PDF 导出,导致这个接口但凡调用一次就 fullgc 几次,最后找不出问题就写了个定时任务隔一段时间重启服务😂
#50 fullGC 频繁,代码不太烂的话,加内存就好了。(省心省力
没有监控吗。一般就是 dump 下来,使用 memory analyzer 分析一下
项目里面有自己用 netty 直接内存池进行分配和释放么?用了加-Dio.netty.leakDetection.level=PARANOID 参数,检测下 netty 侧内存有没有泄漏,隔段时间在日志里搜 LEAK 就行了。如果没有直接玩 netty 内存池,加 #17 提到的参数分析 NMT ,多收集几次,看下具体哪个区域在不断增大,收集更多的信息,另外最好把 jdk 版本贴出来,遇到过 openjdk 连续几个小版本反射导致内存泄漏,如果 jdk 小版本版本号太小,最好直接升级到小版本较高的版本
感谢 项目中没有用到 netty 我去加启动参数看看
我上面没有细看你的命令,直接断定你的程序存在直接内存泄漏,这其实不太对。又看了眼你的命令,堆内存给了 2G ,一周跑下来 2.6G ,其实感觉很可能是正常的,因为命令里只限制堆内存,其他区域并没有任何限制,至少把 MaxDirectMemorySize 、ReservedCodeCacheSize 、MaxMetaspaceSize 这几个参数填了。如果还限制不住,可以考虑增加-Djdk.nio.maxCachedBufferSize 、-DMALLOC_ARENA_MAX 、-DMALLOC_MMAP_THRESHOLD_这些参数的配置,并且给比较小的值,如果还是不断增长,再考虑内存泄漏。
而内存的总量保持不变。
是如何确认内存不断增大呢,通过 top 吗
老生常谈的问题了, k8s limit pod 的内存限制, 触发 OOM 就释放了,就是这么粗暴。
先 dump 简单分析下再看其它问题.
有 buffer 没释放掉
7* 24 后台线程不能在 循环里声明变量,否则内存会爆。
感觉没问题,还有堆外内存呢,Metadata ,Codecache 等。使用中 jit 会把热点字节码编译成机器码放到 codecache 中,这个增长不会一直持续。
Netty 的 buffer 是基于计数器来决定是否释放的,每个 handler 有义务对不再使用的 buffer 做减少引用的操作,继承了 SimpleChannelInboundHandler 的话会自动执行一次减少引用的行为,在 handler 链的末端会再次做一次减少引用的动作,如果 handler 链执行完,buffer 的引用计数为 0 就会被释放,所以有些业务需要会通过 ReferenceCountUtil.retain() 增加引用计数,避免 buffer 被释放,不小心会导致 buffer 泄露,实际上在 netty 中已经内置了泄露分析的工具,可以考虑在测试环境添加 io.netty.leakDetectionLevel 参数来分析是否存在 buffer 泄露。
几个月前打开 ie 就自动跳转到 edge ,在 internet 选项中把“启用第三方扩展”前面的勾去掉后就不会跳转了。 刚才打开 ie 发现提示 ie 已与 edge 合并…
首先排除使用路由器或电脑本地搭建的方法。 我有域名,但是没有服务器,感觉服务器很贵。 哈哈哈哈,你都排除本地搭建系统了,难道租用别人的机器搭系统吗?更贵。 在线乞讨服务…
目前用 TTRSS+RSSHUB ,但手机端支持不是很好,想问问看有没有对应的客户端,能同步已读、未读的。 -- 目前需求场景是 以 PC 端为主的 RSS 阅读 偶尔(比如…