`
SK.Heman
  • 浏览: 9726 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

性能问题

阅读更多
(转帖)这个贴用于记录自己碰到过的一些Java问题,会根据经验不断增加,以便总结,:)

case: 某应用在运行个一两天后就会把物理内存耗光
解决过程:
1、先按经验查了下有没有错误使用Inflater和Deflater,没有,于是继续;
2、继续上perftools,看看到底什么原因造成的,结果在6u21版本上看到的很诡异,是JVM_handle_linux_signal占了最多,觉得不靠谱,于是先升级成了6u26;
3、再分析,看到os::malloc占用了最多,但其他的就完全没头绪了;
4、在@JosephWang_CN的帮助下,图形分析下了perftools的stack trace,才发现还是unsafe_allocate的地方,但这次现象和上个case不同,不同点在于这次是由于cms gc的bug造成的,bug id为7112034,这个bug会造成即使direct bytebuffer已经无引用了,但在cms gc时其并不会被清除掉,而要等到full gc才会清除,官方版本在6u32中修复此bug(这个很容易验证,如果没开启ExplicitGCInvokesConcurrent,用jmap -histo:live强制触发下);
5、在fix了这个bug的前提下,还需要限制-XX:MaxDirectMemorySize的大小才行,否则可能会出现还没到触发cms gc时,物理内存就用完了的现象。
总结:
根据多次排查Java Heap外内存泄露的问题,目前的经验为:
1、先查查看有没有错误使用Inflater和Deflater,如有则基本就搞定了;
2、多执行几次jmap -histo:live,看看内存会不会下降,如果会的话,多数和GC的bug有关;
3、perftools,对调用次数的那列进行排序(pprof –text … | sort -n -r -k4),如果看到是Unsafe_Allocate比较多,且为server端应用,则通常说明是哪个地方分配了Direct ByteBuffer,但来不及释放引用,然后嘛,就是用btrace跟踪下看看谁干的,分析原因。

case: 某应用在压测一段时间后就会把物理内存耗光
解决过程:
1、从gc log以及jstat信息来看,java heap内的内存消耗并不多,但堆外消耗非常严重,导致了物理内存被耗光;
2、于是装上google perftools,看看堆外到底是什么原因造成的消耗;
3、分析了下google perftools的内存malloc消耗,主要是调用Unsafe.allocate造成的;
4、通常调用Unsafe.allocateMemory来分配内存的,只有Direct ByteBuffer和AWT,这应用是没用AWT的,Direct ByteBuffer倒是用到了;
5、网上google了一会,找到一个貌似和这个应用的场景很像的内存泄露的现象,具体信息请见:http://t.co/S9jvDt8O,号称是SocketChannel.write的时候,如果是Direct ByteBuffer会导致memory leak,而且Trustin Lee(Mina/Netty的作者)也这么说的:”it’s a known bug”;
6、于是建议应用的同学将ByteBuffer的地方改成不用direct方式;
7、改完后,重新压测,物理内存消耗是没那么严重了,但java heap用满了后回收不了了;
8、于是dump内存,用mat分析后发现是由于这个应用本身处理上的一些缺失造成的,简单说下,这个应用是一个基于mina的应用,而应用没有对session上的发送请求做限流,而mina来不及发送,导致积压了很多WriteRequest,从而内存被耗光了;
9、对这个问题的解决方法是:限流,当未发送的字节数到达某个比率后,就暂时先不发送了,或者报错等等,用netty能对这个现象有一定的缓解,但限流动作还是要做,否则可能会出现接收方处理慢,从而导致发送方内存用完的现象。

case: 某应用在压测时很容易出现promotion failed的现象
解决过程:
1、从promotion failed时的gc日志来看,状况为新生代中有1.5g的对象存活,旧生代此时的空余空间为4g,足以放下新生代存活的这些对象,于是只能猜测可能是cms gc的情况下旧生代的碎片问题导致的,其实心里是不太相信的,因为这空间空闲了如此的多呀;
2、首先增加-XX:+PrintPromotionFailure看看Promotion Failed的时候是不是有很大的对象要晋升到旧生代,结果打出来的日志显示在晋升的时候失败的竟然只是申请262146个block的空间而已,这是在开启了压缩指针的情况,因此每个block为4个字节;
3、还是不能确定,于是增加-XX:+CMSDumpAtPromotionFailure,看看OLD Gen的碎片状况;
4、打出来的信息显示old gen拥有最多free block的chunk也只有99977个而已,有53w+个chunk,里面大部分都只有999个free block,可见碎片相当严重;
5、到这步只是确定了碎片很严重,暂时能想到的只有每天半夜的时候主动执行下jmap -histo:live,尽可能减少碎片吧,如果后续有什么改进的动作,再来记录。

case: 某应用在发布的过程中突然crash了几台
解决过程:
1、应用crash后hs_err*.log以及core.[pid]文件都没生成;
2、先打开core dump;
3、crash后gdb core dump看:

(gdb) bt
#0  0x00002ba466f82971 in ?? () from /opt/jdk-1.6.0_26/jre/lib/amd64/server/libjvm.so
#1  0x00002aab78a7e20d in Java_java_net_SocketOutputStream_socketWrite0 ()
   from /opt/jdk-1.6.0_26/jre/lib/amd64/libnet.so
4、看到上面的core dump完全木有头绪,后来@rednaxelafx 介入处理,才知道原来jstack是可以跟core dump文件提取出当时java程序的状况的;
5、jstack出来一看,发现程序里有个地方无限递归…so…
总结:
@rednaxelafx接着又进一步分析了为什么没有生成hs_err*.log,是因为从jdk 5.0以后的版本,hs_err*.log就是在crash的那个线程来生成,而这个案例中crash时的那个线程无限递归,而且正在native栈上,栈空间被消耗光了,所以hs_err*.log文件就没生成出来。

Case: 某应用偶尔会出现极为频繁的Promotion failed,导致cms gc切换为串行full gc,从而响应变得超级慢
解决过程:
1、从promotion failed的日志来看,应该是在那段时间内内存被消耗光了造成的,因此在promotion failed的时候dump了内存;
2、可惜dump出来的那个内存文件打不开,几次都是如此;
3、还好我们自己定制的jdk版本这个时候发挥了作用,这个版本中有个功能是如果代码中有地方分配了超级大的数组,会打印出堆栈;
4、在某次出问题的时候,我们看到了这样的堆栈信息:

==WARNNING==  allocating large array: thread_id[0x00002aaac2d85800], thread_name[ajp-0.0.0.0-8009-48], array_size[782611408 bytes], array_length[195652847 el
ememts]
        at java.util.Arrays.copyOf(Arrays.java:2734)
        at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
        at java.util.ArrayList.add(ArrayList.java:351)
        at net.sf.json.JSONArray._fromJSONTokener(JSONArray.java:1154)
        at net.sf.json.JSONArray.fromObject(JSONArray.java:147)
        at net.sf.json.util.JSONTokener.nextValue(JSONTokener.java:358)
        at net.sf.json.JSONObject._fromJSONTokener(JSONObject.java:1128)
        at net.sf.json.JSONObject._fromString(JSONObject.java:1317)
        at net.sf.json.JSONObject.fromObject(JSONObject.java:185)
        at net.sf.json.JSONObject.fromObject(JSONObject.java:154)
        at 我们自己的代码...
5、有这个堆栈后就可以知道是由于自己的代码这个地方触发了json创建了一个巨大的array;
6、于是怀疑是我们传给了json一个很大的String,就先在应用层做了个保护,超过一定大小的String就直接抛错;
7、加上了这个保护后还是出问题了;
8、因此怀疑是json内部有bug,导致传了某种格式的String后就会出现死循环什么的;
9、“神”看代码后,构造了一个这样的String s = “{tag:[0,1,”;然后调用JSONObject.fromObject(s),就会OOM;
10、于是修改了json的代码,修复此bug…

Case: 某应用cms gc时concurrent-mark阶段应用竟然没有响应…
解决过程:
1、在cms gc进行的过程中用pstack采集目前java进程正在做什么;
2、从日志分析来看貌似是在concurrent-mark时,很多的java线程在分配内存的时候被锁住了…
3、将相关信息发给官方的gc dev maillist,只是得到了升级到6u28试试的建议…
目前问题尚未解决,先在此mark下,和这个url提到的问题基本一致:http://t.co/EU92I8nN

Case: 某应用cms gc非常频繁,并且很容易出现concurrent mode failure造成Full GC
解决过程:
1、从gc日志来看,cms gc每次在旧生代使用才到18%左右的时候就触发了,而设置的触发比率是80%,并且不允许JVM自行触发;
2、每几次cms gc还会偶尔出现concurrent mode failure的现象,看了下,这时旧生代的空间是非常充足的;
3、根据cms gc的触发机制,猜测是permGen的问题造成的,于是通过jstat -gcutil看了下permGen的占用比例,果然过一会就超过下92%(不过这里有个问题,就是permGen其实是还没达到MaxPermSize的,看来在cms gc的情况下,maxPermSize要采用不同策略);
4、于是适当的调大permGen,不过仍然没有解决,原因是permGen增长实在太快了;
5、应用方发现有地方会不断的创建classLoader,加载class,因此导致了permGen的增长,修改后问题解决。
总结:
CMS GC的日志其实打的有些问题,应该把cms gc触发时的原因输出下;
另外就是在大部分情况下,只要不是cms gc触发的比例设置的太有问题,如果cms gc频繁或full gc频繁都是应用本身的问题造成的。

Case: 某应用出现启动后集群中部分node成功,部分node失败
解决过程:
1、失败的node抛出的是NoClassDefFoundError,这些node在环境上和应用包上是完全一致的,因此猜想是classloader装载class时出现了什么问题;
2、在启动参数上增加了-XX:+TraceClassLoading,想看看成功的node和失败的node是不是从第一个地方加载的相应的类,悲催的是成功的node加上了这参数后启动超慢,于是只好放弃;
3、由于不能用TraceClassLoading,只好从ClassLoader方面来跟踪这个类的加载,于是从应用层上做了相应的分析,找出了相应的classloader,然后用btrace相应的进行了跟踪,才终于发现成功的node和失败的node装载此类时不是从同一地方装载的,而其中有一个地方的这个类引用了一个不存在的类,于是就出现了NoClassDefFoundError。
总结:
在经过分析后,猜想是在这两个不同的node上classloader在list一个目录下的文件时,出现了顺序不同的现象,于是后来写了一个简单的程序在两个node上list那个目录的文件,发现返回的顺序果然不同,这个具体的原因为File.listFiles最后会调用到readdir函数,而这个函数返回的文件列表是按inode number排序的,因此在每台linux机器上确实有可能不同,当一个目录下有两个jar中有相同名字但不同内容的class时(话说这也是java应用中比较麻烦的问题,这个专门写篇blog来说下,java 8的模块化真的非常重要),就悲催了,一个保护做法是在实现classloader时,最好是先对listFiles排下序,避免集群中node出现表现不一致的问题。

Case: 某应用GC频繁但不一直不抛OOM的问题
解决过程:
这个应用是期待在内存不够的情况下快速抛出OOM的,但在执行中却发现执行了4个多小时的Full GC,就是没有抛OOM,导致应用出现了问题,从GC代码来看,目前要比较快的触发OOM,只能是调整GCTimeLimit和GCHeapFreeLimit,不过都不好调,后来暂时是靠调整了GCHeapFreeLimit来帮助快速抛出OOM。

Case: 某应用堆外内存泄露的bug
具体解决过程可参考这篇blog:http://blog.bluedavy.com/?p=205和这篇blog。
总结:
堆外内存泄露基本就是靠google perf-tools来查找了,目前来看堆外内存泄露基本都是使用Deflater,却没有显式调用end造成的。

Case: 某应用压测时压力上不去的问题
解决过程:
1、查看压测的目标服务器的cpu、网卡流量,发现都没到瓶颈;
2、继续查看压测的目标Server的线程状况,发现Server的线程数也没到瓶颈,有个诡异的现象是随着客户端施加的压力上升,服务器端线程数也没上升,而且网卡流量也没上升;
3、于是猜测是客户端本身的问题,客户端的CPU、网卡流量也没到瓶颈,但发现客户端的线程数随着施加的请求数增加,也没上升,因此猜想是客户端这个地方的线程数已经达到了最大值;
4、由于代码是第三方的,于是用btrace写了个脚本,跟踪查找了该线程池的最大线程数,发现果然是这个最大线程数比较小,因此做了相应的修改,放大最大线程数,继续压测就OK了。
ps: 这个Case还出现了一个状况,就是客户端的网卡流量随着施加的压力上升,却没发生变化,因此猜测是网络上有流量限制…
总结:
从查这次的问题来看,在压测时压力上不去时,需要查看从请求发起到响应返回的整个过程,资源的消耗状况,是否某个地方资源消耗到极限了,如果硬件资源未到极限,通常会是线程blocked或线程被消耗完了。

Case: 某应用GC频繁的问题
这个专门写了一篇blog来描述,具体请见:http://blog.bluedavy.com/?p=290

Case: 某应用一直没响应。
解决过程:
1、jstack多次后分析,很多的线程都在Blocked状态,等待一把锁,而持有这把锁的线程一直停在了Log4j的ConsoleLog的write上;
2、于是问题就集中到为什么ConsoleLog write的时候竟然会停住,最早猜测的原因是console是不是也输出到了一个文件,而这个文件出问题了,但经过检查发现一切正常;
3、通过ps auxf查看脚本看看console有没有输出到文件,发现这个脚本嵌套了好几层,但都输出到了外部的文件,而外部这个文件是没什么问题的;
4、仔细查看发现这个Java进程是在代码里通过调用脚本启动的,猜想是不是没有正确处理标准输出流和错误流造成的,于是翻看代码,发现代码只处理了输出流,但没处理错误流,并且在处理输出流时只处理了10000行,超过10000的时候就没再去读了,对于这种未将console重定向到外部文件的场景,linux会将其写到一个缓冲区,缓冲区写满后就会导致应用程序阻塞住,这个在Java的API上也有说明:
The parent process uses these streams(Process.getOutputStream(), Process.getInputStream(), Process.getErrorStream()) to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
5、到这步后就可以确认问题的原因了。
解决方法:
1、把输出到Console的Logger方式去掉了,这样自然就没问题了;
2、程序上修改,不是读到1w行就不读了,而是一直读到没有输出流和错误流了才结束,通常来说比较正确的做法请见这篇贴:http://goo.gl/sllmv
总结:
在Java中启动外部程序时一定要注意正确处理输出流和错误流。
分享到:
评论

相关推荐

    setInterval 引起的性能问题

    然而,如果不正确地使用,`setInterval`可能导致各种性能问题。这篇博客文章“setInterval引起的性能问题”探讨了这些问题以及如何避免它们。 首先,`setInterval`的定时并不精确。它并不是在指定间隔的精确时间点...

    高通QXDM常规操作及外场常见性能问题分析思路-.pptx

    高通QXDM常规操作及外场常见性能问题分析思路 QXDM(Qualcomm eXtensible Diagnostic Monitor)是高通终端调测、原始 Log 抓取工具,QCAT(Qualcomm Crash Analysis Tool)是高通 Log 查看、分析工具。下面是 QXDM ...

    10.1.2 redis常见性能问题和解决方案.md

    10.1.2 redis常见性能问题和解决方案

    J2EE常见应用性能问题

    ### J2EE常见应用性能问题解析 在Java2平台企业版(J2EE)的应用开发与维护中,性能问题是不可避免的挑战。本文旨在深入探讨J2EE应用中常见的性能问题,以及如何有效地检测与解决这些问题。我们将从标题“J2EE常见...

    如何发现前端的性能问题-刘杰

    一个挺不错的PPT 如何发现前端的性能问题-刘杰

    解决JAVA服务器性能问题研究分析.doc

    【JAVA服务器性能问题研究分析】 在Java服务器的开发和运维过程中,性能问题是一个关键的考虑因素,尤其是在高负载环境下。解决此类问题需要深入理解服务器性能分析的概念和工具,以及如何在模拟环境中有效地测试和...

    Node.js-诊断您的Node.js性能问题

    在Node.js开发过程中,性能问题可能会严重影响应用的效率和用户体验。`Node.js-诊断您的Node.js性能问题`这个主题旨在帮助开发者识别并解决这些问题。在本文中,我们将深入探讨Node.js性能诊断的关键技术和工具,...

    常见问题:如何使用Oracle AWR报告来诊断数据库性能问题

    Oracle AWR报告是Oracle数据库中用于诊断性能问题的重要工具,它能够提供数据库在特定时间段内活动的详细统计信息。AWR(Automatic Workload Repository)是Oracle企业管理器(Enterprise Manager)的一个组成部分,...

    性能数据库问题诊断分析

    一旦数据库出现崩溃或性能问题,将导致系统无法正常运行,给企业带来客户流失、利润下降,甚至更严重地,引起不良社会影响。因此,对数据库进行性能监控与问题诊断分析至关重要。 在进行数据库性能监控和问题诊断时...

    java代码性能问题检查计划及方案

    Java代码性能问题检查计划及方案 在Java编程中,性能问题往往是开发者关注的重点。虽然Java语言自身具有高效、跨平台的特性,但程序的运行效率却更多地取决于开发者的设计和编码习惯。本方案旨在提供一个详细的检查...

    Domino服务器性能问题诊断与排除手册.doc

    【Domino服务器性能问题诊断与排除】在IT领域,尤其是 Lotus Domino 系统管理中,服务器性能问题的诊断和排除是一项关键任务。Domino服务器作为企业级应用平台,其性能直接影响到用户的工作效率和系统的稳定性。本...

    从Db2 package 层面优化OLTP系统的性能(2)在实践中遇到的package相关性能问题.doc

    在本文中,我们将探讨几个在实际操作中遇到的Db2 Package相关的性能问题,以及如何解决这些问题。 首先,我们要明确,无论SQL语句是动态的还是静态的,无论是通过何种编程语言(如Java的JDBC,或是C++的CLI)执行,...

    Java性能调优 6步实现项目性能全面升级+面试高频性能问题讲解.rar

    Java性能调优 6步实现项目性能全面升级+面试高频性能问题讲解视频教程分享,性能优化的N种企业级解决方案,囊括了【数据库优化】、【Tomcat优化】、【JVM优化】、【垃圾回收】、【Netty优化】、【Nginx优化】、...

    Oracle RAC 环境中 gc block lost 和私网通信性能问题的诊断

    Oracle RAC 环境中 gc block lost 和私网通信性能问题的诊断 Oracle RAC(Real Application Clusters)环境中,gc block lost 和私网通信性能问题是两个常见的性能瓶颈问题,本文将对这两个问题进行详细的分析和...

    使用IBM性能分析工具HeapAnalyzer解决生产环境中的性能问题

    使用 IBM 性能分析工具 HeapAnalyzer 解决生产环境中的性能问题 性能分析是企业级应用系统软件不可或缺的一部分,对于业务操作的响应时间和并发数的要求非常高。只有经过不断的调整优化,才能达到资源的最大利用率...

    2013-ADC-阿里技术嘉年华PPT下载-D2-前端技术-如何发现前端的性能问题

    前端性能问题的发现方法: 在文件中提到的“如何发现前端的性能问题”可以总结为前端性能优化的重要组成部分,即问题诊断。前端性能问题通常体现在页面加载缓慢、用户交互卡顿等方面。要发现这些问题,开发者可以...

    关于SQL性能问题的探讨.pdf

    针对Oracle数据库的SQL性能问题探讨涉及了多个方面,包括环境差异分析、SQL语句本身优化以及业务层面的调整。在开发使用Spring框架的Web项目时,面对大量表的数据检索问题,文章指出了开发过程中可能遇到的性能瓶颈...

    小设置,大问题——SQL Server性能问题的一个剖析.pdf

    在探讨SQL Server性能问题时,首先需要了解的是SQL Server Profiler(事件探查器)的使用方法。事件探查器是SQL Server的一个工具,它能够记录服务器上发生的事件,如T-SQL语句、存储过程调用等。Danny在遇到企业...

    探究无线网络中的性能问题

    现在,低预算的Wi-Fi网络已经是非常地流行了,但是他们并不是现在仅有的一种无线网络类型。实际上,如果从价格...为了能在无线网络中达到最佳性能,有必要了解一些在Wi-Fi和非Wi-Fi无线网络中都普遍存在的一些问题。

    华为手机功耗性能问题解决指导V2.0 (三方开发者).pdf

    华为手机功耗性能问题解决指导V2.0 华为手机功耗性能问题解决指导V2.0是华为提供的一份指导文件,旨在帮助第三方开发者解决华为手机中的功耗性能问题。这份指导文件提供了详细的解决方案指导流程,旨在帮助开发者...

Global site tag (gtag.js) - Google Analytics