|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
在ruby里才是一切皆对象。当然我不并不是很了解ruby,但是ruby确实是将语法简化得很好。以下是Java使用在运转经常见的一些成绩,总结了运转时黑盒体例的一些排查办法,也但愿看到的同砚能赐与增补,不管是增补碰着的成绩,仍是增补办理办法。
类装载的相干成绩
写过Java代码的同砚估量都碰着过ClassNotFoundException/NoClassDefFoundError/NoSuchMethodException(另有一个罕见的ClassCastException就不在这里说了)。
当碰着ClassNotFoundException/NoClassDefFound时,假如很断定这个class应当是从哪一个路径装载的,则能够往响应的路径找下是不是有对应的class文件存在,比方web使用一般会在*.war(ear)/WEB-INF/lib或classes目次下,关于lib下的jar包,可经由过程写个小剧本jar-tvf的体例找找;
如不断定class是从哪装载的,则能够先看看日记里是不是有仓库信息,假如有的话则能够看到详细是哪一个ClassLoader完成在装载class,以后则能够经由过程www.grepcode.com或jar包反编译(保举一个挺好用的反编译工具)看看详细是从哪装载的class;
如日记中没有,则能够用btrace来跟踪下抛出以上两个非常的仓库信息,btrace剧本相似以下:
1
2
3
4
5
6
7
8
9
10
11
importstaticcom.sun.btrace.BTraceUtils.*;
importcom.sun.btrace.annotations.*;
@BTracepublicclassTrace{
@OnMethod(
clazz="java.lang.ClassNotFoundException",
method="<init>"
)
publicstaticvoidtraceExecute(){
jstack();
}
}
拿到仓库信息后,能够持续利用下面的办法举行排查,在确认了class装载的地位后,则可将响应的class/jar加上便可。
这里另有个NoClassDefFoundError排查的case,感乐趣的话能够看看。
当碰着NoSuchMethodException时,一般是因为不存在必要的class版本或class版本抵触酿成的,在这类情形下,可经由过程在启动参数上增添-XX:+TraceClassLoading,重启后在日记里看看此class是在哪load的,然后能够在对应的路径下用jar-tvf找找是否是有准确的版本的jar存在,一般大概会发明是版本抵触酿成的,关于版本抵触的成绩一般必要删失落有抵触的版本的jar,关于没有准确版本的,则必要用准确版本的jar交换失落(固然,这类一般还会呈现一些恶心的成绩,比方和容器/框架的jar抵触等)。
cpuus损耗高
当呈现cpuus损耗高时,一般的排查办法以下。
从履历下去说,有些时分是因为频仍cmsgc或fgc酿成的(频仍的意义是差未几每次cmsgc或fgc一停止后又立即持续),在gclog是纪录的情形下(-Xloggc:),可经由过程gclog看看,假如没翻开gclog,可经由过程jstat-gcutil来检察,如是gc频仍酿成的,则可跳到前面的内存成绩|GC频仍部分看排查办法。
如不是下面的缘故原由,可以使用top-H检察线程的cpu损耗情况,这里有大概会看到有一般线程是cpu损耗的主体,这类情形一般会对照好办理,可依据top看到的线程id举行十六进制的转换,用转换出来的值和jstack出来的java线程仓库的nid=0x[十六进制的线程id]举行联系关系,便可看到此线程究竟在做甚么举措,这个时分必要进一步的往排查究竟是甚么缘故原由酿成的,比方有多是正则盘算,有多是很深的递回或轮回,也有多是毛病的在并发场景利用HashMap等,比方这里另有一段随即天生字符串的耗cpu的代码case。
如top-H看到的损耗cpu的线程是不休变更的,就对照贫苦了,有个同砚写了个剧本主动的往经由过程top-H看到的损耗cpu的线程找到对应的Java线程仓库,在这类情形下能够用这个剧本往尝尝,假如看到的线程仓库的确是对照耗cpu的举措,则基础能够定位到。
如仍旧看不出,则能够实验多jstack看看,然后多看看是不是常常有一些耗cpu的举措在分歧的线程不休的呈现。
如可以使用perf,则可用perftop看看cpu损耗的热门,不外默许的版本上只能看到jit后的代码,因而大概会对照难对应到详细的代码,这里有一个基于perf排查的Java使用cpuus诡异征象的case。
总结来讲,cpuus损耗高的成绩排查仍是有必定庞大性,比方之前我碰着过反序列化的对象对照年夜,哀求又十分频仍,招致cpuus损耗增高了良多,但事先的呆板内核版本不敷,不撑持perf,从jstack等等上都看不出甚么,厥后是因为从营业监控的变更上才排查出成绩。
内存成绩
只管JVM是主动办理内存的分派和接纳的,但Java程序员们仍是会常常碰着林林总总的内存成绩。
最多见的第一个成绩是java.lang.OutOfMemoryError,估量写Java的同砚都碰着过。
在日记中大概会看到java.lang.OutOfMemoryError:Unabletocreatenewnativethread,能够先统计下今朝的线程数(比方ps-eLf|grepjava-c),然后能够看看ulimit-u的限定值是几,如线程数已到达限定值,如限定值可调剂,则可经由过程调剂限定值来办理;如不克不及调限定值,大概创立的线程已良多了,那就必要看看线程都是那里创立出来的,一样可经由过程btrace来查出是那里创立的,剧本相似以下:
1
2
3
4
5
6
7
8
9
10
11
importstaticcom.sun.btrace.BTraceUtils.*;
importcom.sun.btrace.annotations.*;
@BTracepublicclassTrace{
@OnMethod(
clazz="java.lang.Thread",
method="start"
)
publicstaticvoidtraceExecute(){
jstack();
}
}
在找到是那里创立形成了后,以后就能够想举措办理了,比方这类情形下罕见的有多是用了Executors.newCachedThreadPool这类来创立了一个没限定巨细的线程池。
另有一种多是ulimit-u的限定还没到,内存也余暇,但仍旧创立不了,这有多是因为在2.6.18/32内核上kernel.pid_max默许的32768酿成的,这个值实在间接限定了最多能创立的线程数就是32768(即便ulimit-u的值比这年夜也没用)。
java.lang.OutOfMemoryError:HeapSize或GCoverheadlimitexceeded也是罕见的征象,在呈现了这两种征象的情形下,最主要的是dump出内存,一种办法是经由过程在启动参数上增添-XX:+HeapDumpOnOutOfMemoryError,另外一种办法是在当呈现OOM时,经由过程jmap-dump猎取到内存dump,在猎取到内存dump文件后,可经由过程MAT举行剖析,但一般来讲仅仅靠MAT大概还不克不及间接定位到详细使用代码中哪一个部分酿成的成绩,比方MAT有大概看到是某个线程创立了很年夜的ArrayList,但如许是不敷以办理成绩的,以是一般还必要借助btrace来定位到详细的代码,能够看看这两个OOM排查的case。
java.lang.OutOfMemoryError:PermGenSpace,当碰着这个征象时,能够经由过程调剂permgensize来尝尝,假如缩小了一点后仍是不休的损耗,则能够经由过程btrace来跟踪下装载class的征象,剧本相似以下:
1
2
3
4
5
6
7
8
9
10
11
importstaticcom.sun.btrace.BTraceUtils.*;
importcom.sun.btrace.annotations.*;
@BTracepublicclassTrace{
@OnMethod(
clazz="java.lang.ClassLoader",
method="defineClass"
)
publicstaticvoidtraceExecute(){
jstack();
}
}
另有一种OOM是nativeOOM,就是物理内存被耗光,关于这类征象,办理起来会贫苦一些,从履历下去说,NativeOOM有很也许率是因为毛病利用Deflater/Inflater酿成的,以是在碰着这类征象时,能够先用btrace跟进下看看利用了Deflater/Inflater的有无显式往挪用end办法;别的一种罕见的缘故原由是利用DirectByteBuffer的场景(比方NIO框架等),如利用了DirectByteBuffer的对象是对照长存活的,当其被转到旧生代后,在fgc没触发前,实在其占用的JVM堆外内存是不会被开释的,在这类情形下,能够做的一个实验是先强迫实行几回fgc(jmap-histo:live),然后看看堆外内存的利用是否是下落了,假如下落了则申明是这个成绩,关于这类成绩,能够用的一个办理计划是增添一个启动参数:-XX:MaxDirectMemorySize=500m来完成当DirectByteBuffer利用到500m后自动触发fgc往返收(究竟设置成多年夜使用能够本人调剂)。
如下面两招都没用,则必要挂上googleperf-tools来跟踪下看看究竟是那里在malloc,不外这里看到的是c仓库上的工具,因而必要本人想举措依据这个对应到java的代码上往。
关于nativeOOM,这篇文章里有一些详细排查的case。
除OOM外,另有大概会碰着GC频仍的成绩(有良多同砚会问我,究竟甚么算频仍,我以为基础上假如每隔10s或更短工夫就来一次cmsgc或fullgc才算得上吧)。
GC频仍的征象呈现时,假如发明cmsgc或fullgc后,存活的对象一直良多,这类情形下能够经由过程jmap-dump来猎取下内存dump文件,然后经由过程MAT/btrace来定位到详细的缘故原由。
如cmsgc或fullgc频仍,但触发时old另有余暇空间,这类情形下有大概会是因为失望战略形成,详细能够看看这篇文章里的几个cases,这类情形下一般的办理办法能够是调年夜old或减小young。
如不是失望战略酿成的,关于接纳cmsgc的情形,另有多是cmsgc的碎片成绩酿成的,这类情形下能够经由过程强迫实行下jmap-histo:live来触发fgc,不外悲催的是cmsgc的碎片成绩是无解的,临时只能靠强迫触发fgc等来制止在岑岭期时呈现成绩。
关于cmsgc而言,另有大概会呈现promotionfailed或concurrentmodefailure成绩,详细也能够看看下面那篇文章的cases。
Java历程crash或加入
Java历程crash或无端加入也是会碰着的征象,关于历程crash,默许情形下jdk会天生hs_err[pid].log的文件,coredump翻开的话也会天生coredump文件,当历程crash产生时,能够先看看hs_err[pid].log,如没找到此文件,但有coredump文件,有大概的缘故原由是代码中呈现了无穷递回或逝世轮回,可经由过程jstack
1
[coredump文件]来提掏出java的线程仓库,从而详细定位到详细的代码;若有hs_err[pid].log和coredump文件,则必要详细缘故原由详细排查,这个对照贫苦,罕见的大概会有下面的nativeoom(另有多是32bit呆板,但java历程已请求了凌驾3g的地点空间),某些代码jit编译出成绩了(可经由过程指定某些代码不让jit编译来制止,但会影响功能:-XX:CompileCommand=exclude,类名/办法名)等。
在下面的招还有效时,能够实验dmesg看看是否是体系出了甚么成绩或体系自动杀失落过历程(比方内存超越限定等),仍旧没找到缘故原由的话必要往翻翻使用的日记,看看是否是能找到甚么线索,由于有些时分是使用上自动加入了(关于使用自动加入的成绩可经由过程btrace来排查是否是有自动挪用过System.exit)。
唉!都是钱闹的1.Swing和.net网页编程开发比较------从市场份额看.net网页编程开发主要占据大部分的中小型和中型的的桌面开发,原因是它封装了很多工具 |
|