如果发现java程序内存耗用过大,如何解决/调优

ffeitian 发布于 2017年12月04日
tinyfool 等1人欣赏。

1 设置jvm参数,调整内存使用,设置上限

2 优化代码,减少内存的使用(

例如:

1)回收使用object,建立object pool,

2)在可行的地方使用primitive type而不用object以减少内存的使用

3)查看代码,减少内存泄漏

本人编码经验不丰富,以上仅是纸上谈兵,特别是从未用调整过jvm的参数,还请高手多多指教,如果有一些项目中在用的经验就妙极了

谢谢

共9条回复
tinyfool 回复于 2017年12月04日

这个可能还是要看具体的情况

梦中醒不过来 回复于 2017年12月05日

Java从入门到放弃

alec_huang 回复于 2017年12月05日

没写过Java,用.NET的经验回答你,反正差不多。看了你的问题,大致想明白为什么之前老赵嘲讽国内javaer的水平,大部分代码都没写好,就一心想着JVM调优。最后都成了“架构师”……

  1. 基本上,不要动改JVM参数的想法。
  2. 了解Java内存布局,想想你代码里有哪些内存浪费
  3. 迎合GC编程,而不是调整GC。JVM参数开放的那么多,实际上,就算是R神也很难说准改那个参数能造成什么影响。
  4. 大致手段也就是,大对象复用,避免LOH碎片,极端一点的,编写不通用代码。
  5. 以上都是废话,把你系统伸缩性弄好,直接走分布式,堆机器,当架构师岂不美哉。
tinyfool 回复于 2017年12月05日

3楼 @alec_huang 逻辑是对的

不过他说的jvm调优,其实就是设置默认内存大小之类的小操作

其实,我之前懒得讲的一个问题是,没有不基于profile的调优,基于任何理论和经验的调优,都是撞大运,必须经过profile

denger 回复于 2017年12月05日

你这个问题太泛了。仅仅「java程序内存耗用过大」这不是定位到的问题,表现是什么(OOM了还是GC不了),具体哪个对象(或数据)导致的?导致的原因是什么(代码级的)?为什么这个原因会导致问题(设计考虑不周还是使用不当)?

既然说到如何去做调优,个人经验来说,三步曲

  1. 发现问题:先找到需要优化的点是什么,比如通过 gclog GC 发现 FGC 频率过高,比如 OOM
  2. 定位问题:实际上就是分析问题的过程,通过借助 JVM 工具(如jmap jstat) 或 linux 中各类 trace工具来收集相关数据(线索),再结合代码对问题进行分析,如有必要的可进行重现,保证定位到的问题的准确性。
  3. 解决问题:你说的第2点,实际上是在这一步才需要做的,而且一定是针对定位到的问题采用针对性的解决方案。

要想提高这方面能力,没有捷径,唯有不断增加知识面(原理方面)的同时并通过排查大量 CASE 来提高经验值。不建议上来就是「优化代码,减少内存的使用」之类的,有一句话叫「过早的优化是万恶之源」。

ffeitian 回复于 2017年12月05日

各位高手讲得太好了。.net, profile, 发现问题,定位问题,解决问题!

发现问题:

1 监控jvm内存(例如使用代码或者工具监控),查看各类object占用空间的大小,然后进行分析

2 工具:gclog GC, jmap, jstat, trace(linux)

定位问题:

1 看哪类对象占用的空间过大,与测试数据的规模不相对应

2 查看是否有内存泄露

解决问题:

1 调优算法。降低算法的空间复杂度。如果有些算法的空间复杂度可以从O(N*N)优化到O(N)甚至O(logN),那么内存使用将降低

2 查看是否有不必要的object,减少这类object

3 减少内存泄露

//--------=====

分析分析分析,实践实践实践

sanqian 回复于 2017年12月07日

我也凑个热闹说一下经验之谈,不高明,但帮我在实际中解决了不少问题。

我通常将情况分为两类,“预期内存占用”和“非预期内存占用”。我不建议一上来就 profile,定位问题其实是个猜测+验证的过程。

预期内存占用

这好理解,比如因业务需要人为加载的缓存。对系统熟悉的情况下,是能判断出来大致合理的内存使用范围。如果超出这个范围(阈值设为 > 2倍的预估内存占用量),那就有问题了。

非预期内存占用

我这经常先用个土办法,至少先问一圈同事是不是往内存塞数据了或者写了一些极有可能需要占用大量内存的代码,这办法笨,但成本小易定位。

最后才采用 profile 的办法。各位见笑,我个人极不喜欢 profile,看到 profile 的结果,找到确切的问题所在其实也是连蒙带猜比较耗时的过程。

其他想法

  • 人比机器贵多了,只要不是严重的 bug 导致 OOM,加点内存就好了。综合来看,程序是不可能达到理想最优状态的。

  • 系统监控和日常运维非常重要,需要定期查看服务器内存的使用情况。如果内存使用率突变,需要分析是用户访问量增加,还是改了程序导致的变化。

  • 程序是逐渐迭代的过程,问题并不是一次性出现。每发一个版本就需要检查日志,新问题肯定是出在新代码上,需要检查的范围也极少,通常只是简单代码 review 就能解决。

  • 对程序整体的架构需要了解。项目哪里有潜在问题,其实和经常上下班的熟悉的路是一样。这点比较难,特别是接手他人的项目或者只是在项目中当个镙丝丁。项目文档就我的经验来看没啥用,细节更不可能从中得知。这一点,更多是通过架构师的管理和员工积极性之间的互动来解决。

lyxing 回复于 2017年12月24日

分两种情况来讲: 1、设计开发时。象前面几楼讲的,思考内存布局、gc特性等,设计和编码时充分考虑后动手。 2、出问题时。大家也都说到,jmap、jstat等profile工具可以让你比较快速确定问题并进一步判断问题代码,最终解决问题。 JVM调整并不是灵丹妙药,但通常调大内存分配量可解决大部分问题。因为很多人就是使用默认参数去跑应用的。

新生代、年老代、永久代的作用和调整的原理很多java开发者不懂;java8永久代被废弃更多人不懂。

我也不懂!

ffeitian 回复于 2017年12月25日 | 更新于 2017年12月25日

牛人好多啊,又来了7楼8楼的牛人

谢谢!

这里出一个小广告:

本人可以帮大家修改英文简历(或者中翻英)。速度有限,每天翻译或者修改一份简历。水平有限,大概可以帮大家改到通顺流利的程度(如果你的英文水平很高,那我帮不到你了:))。

每页简历收费10元RMB

有兴趣可以加我的微信:johninception

登录 或者 注册