没写过Java,用.NET的经验回答你,反正差不多。看了你的问题,大致想明白为什么之前老赵嘲讽国内javaer的水平,大部分代码都没写好,就一心想着JVM调优。最后都成了“架构师”……
3楼 @alec_huang 逻辑是对的
不过他说的jvm调优,其实就是设置默认内存大小之类的小操作
其实,我之前懒得讲的一个问题是,没有不基于profile的调优,基于任何理论和经验的调优,都是撞大运,必须经过profile
你这个问题太泛了。仅仅「java程序内存耗用过大」这不是定位到的问题,表现是什么(OOM了还是GC不了),具体哪个对象(或数据)导致的?导致的原因是什么(代码级的)?为什么这个原因会导致问题(设计考虑不周还是使用不当)?
既然说到如何去做调优,个人经验来说,三步曲:
要想提高这方面能力,没有捷径,唯有不断增加知识面(原理方面)的同时并通过排查大量 CASE 来提高经验值。不建议上来就是「优化代码,减少内存的使用」之类的,有一句话叫「过早的优化是万恶之源」。
各位高手讲得太好了。.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 减少内存泄露
//--------=====
分析分析分析,实践实践实践
我也凑个热闹说一下经验之谈,不高明,但帮我在实际中解决了不少问题。
我通常将情况分为两类,“预期内存占用”和“非预期内存占用”。我不建议一上来就 profile,定位问题其实是个猜测+验证的过程。
这好理解,比如因业务需要人为加载的缓存。对系统熟悉的情况下,是能判断出来大致合理的内存使用范围。如果超出这个范围(阈值设为 > 2倍的预估内存占用量),那就有问题了。
我这经常先用个土办法,至少先问一圈同事是不是往内存塞数据了或者写了一些极有可能需要占用大量内存的代码,这办法笨,但成本小易定位。
最后才采用 profile 的办法。各位见笑,我个人极不喜欢 profile,看到 profile 的结果,找到确切的问题所在其实也是连蒙带猜比较耗时的过程。
人比机器贵多了,只要不是严重的 bug 导致 OOM,加点内存就好了。综合来看,程序是不可能达到理想最优状态的。
系统监控和日常运维非常重要,需要定期查看服务器内存的使用情况。如果内存使用率突变,需要分析是用户访问量增加,还是改了程序导致的变化。
程序是逐渐迭代的过程,问题并不是一次性出现。每发一个版本就需要检查日志,新问题肯定是出在新代码上,需要检查的范围也极少,通常只是简单代码 review 就能解决。
对程序整体的架构需要了解。项目哪里有潜在问题,其实和经常上下班的熟悉的路是一样。这点比较难,特别是接手他人的项目或者只是在项目中当个镙丝丁。项目文档就我的经验来看没啥用,细节更不可能从中得知。这一点,更多是通过架构师的管理和员工积极性之间的互动来解决。
分两种情况来讲: 1、设计开发时。象前面几楼讲的,思考内存布局、gc特性等,设计和编码时充分考虑后动手。 2、出问题时。大家也都说到,jmap、jstat等profile工具可以让你比较快速确定问题并进一步判断问题代码,最终解决问题。 JVM调整并不是灵丹妙药,但通常调大内存分配量可解决大部分问题。因为很多人就是使用默认参数去跑应用的。
新生代、年老代、永久代的作用和调整的原理很多java开发者不懂;java8永久代被废弃更多人不懂。
我也不懂!