1.查找应用的pid
2.查找pid对应下的线程的哪些id过高
3.jstack pid连续两次获取堆栈的信息,查看变化,以及对应的线程
Thread 5812: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait() @bci=2, line=485 (Interpreted frame)
- org.apache.tomcat.util.net.JIoEndpoint$Worker.await() @bci=8, line=458 (Interpreted frame)
- org.apache.tomcat.util.net.JIoEndpoint$Worker.run() @bci=11, line=484 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=662 (Interpreted frame)
Thread 31207: (state = IN_JAVA)
java.lang.CharSequence) @bci=54, line=3744 (Compiled frame)
- java.util.regex.Pattern$GroupHead.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=28, line=4168 (Compiled frame)
- java.util.regex.Pattern$Loop.matchInit(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=39, line=4311 (Interpreted frame)
- java.util.regex.Pattern$Prolog.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=7, line=4251 (Interpreted frame)
- java.util.regex.Pattern$Begin.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=30, line=3120 (Interpreted frame)
- java.util.regex.Matcher.match(int, int) @bci=86, line=1127 (Compiled frame)
- java.util.regex.Matcher.matches() @bci=6, line=502 (Interpreted frame)
- com.jd.edmfont.action.MailSubscriptionAction.checkAndGetMailAddress() @bci=155, line=236 (Interpreted frame)
- com.jd.edmfont.action.MailSubscriptionAction.mailOrder() @bci=45, line=132 (Interpreted frame)
- sun.reflect.GeneratedMethodAccessor229.invoke(java.lang.Object, java.lang.Object[]) @bci=36 (Interpreted frame)
- sun.reflect.DelegatingMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) @bci=6, line=25 (Compiled frame)
- java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) @bci=161, line=597 (Compiled frame)
- com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(java.lang.Object, com.opensymphony.xwork2.config.entities.ActionConfig) @bci=228, line=450 (Interpreted frame)
- com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly() @bci=14, line=289 (Compiled frame)
com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(com.opensymphony.xwork2.ActionInvocation) @bci=6, line=265 (Interpreted frame)
- org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(com.opensymphony.xwork2.ActionInvocation) @bci=202, line=68 (Interpreted frame)
- com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(com.opensymphony.xwork2.ActionInvocation) @bci=10, line=98 (Interpreted frame)
- com.opensymphony.xwork2.DefaultActionInvocation.invoke() @bci=82, line=246 (Compiled frame)
org.apache.struts2.dispatcher.Dispatcher.serviceAction(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.ServletContext, org.apache.struts2.dispatcher.mapper.ActionMapping) @bci=212, line=546 (Interpreted frame)
- org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.apache.struts2.dispatcher.mapper.ActionMapping) @bci=11, line=77 (Interpreted frame)
- org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) @bci=149, line=91 (Interpreted frame)
- org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) @bci=119, line=235 (Interpreted frame)
- org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) @bci=101, line=206 (Interpreted frame)
- com.jd.common.web.filter.CharsetFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) @bci=166, line=59 (Interpreted frame)
- org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) @bci=119, line=235 (Interpreted frame)
org.apache.catalina.connector.CoyoteAdapter.service(org.apache.coyote.Request, org.apache.coyote.Response) @bci=158, line=291 (Interpreted frame)
- org.apache.coyote.http11.Http11Processor.process(java.net.Socket) @bci=514, line=859 (Interpreted frame)
- org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(java.net.Socket) @bci=82, line=602 (Interpreted frame)
- org.apache.tomcat.util.net.JIoEndpoint$Worker.run() @bci=41, line=489 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=662 (Interpreted frame)
Thread 31203: (state = IN_JAVA)
- java.lang.Character.codePointAt(java.lang.CharSequence, int) @bci=5, line=2335 (Compiled frame; information may be imprecise)
- java.util.regex.Pattern$CharProperty.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=10, line=3344 (Compiled frame)
- java.util.regex.Pattern$Loop.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=139, line=4304 (Compiled frame)
- java.util.regex.Pattern$GroupTail.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=70, line=4227 (Compiled frame)
- java.util.regex.Pattern$GroupHead.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=28, line=4168 (Compiled frame)
- java.util.regex.Pattern$Loop.matchInit(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=39, line=4311 (Interpreted frame)
- java.util.regex.Pattern$Prolog.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=7, line=4251 (Interpreted frame)
- java.util.regex.Pattern$Begin.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=30, line=3120 (Interpreted frame)
- java.util.regex.Matcher.match(int, int) @bci=86, line=1127 (Compiled frame)
- java.util.regex.Matcher.matches() @bci=6, line=502 (Interpreted frame)
- com.jd.edmfont.action.MailSubscriptionAction.checkAndGetMailAddress() @bci=155, line=236 (Interpreted frame)
- com.jd.edmfont.action.MailSubscriptionAction.mailOrder() @bci=45, line=132 (Interpreted frame)
- sun.reflect.GeneratedMethodAccessor229.invoke(java.lang.Object, java.lang.Object[]) @bci=36 (Interpreted frame)
- sun.reflect.DelegatingMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) @bci=6, line=25 (Compiled frame)
- java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) @bci=161, line=597 (Compiled frame)
- com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(java.lang.Object, com.opensymphony.xwork2.config.entities.ActionConfig) @bci=228, line=450 (Interpreted frame)
- com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly() @bci=14, line=289 (Compiled frame)
- com.opensymphony.xwork2.DefaultActionInvocation.invoke() @bci=111, line=252 (Compiled frame)
com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(com.opensymphony.xwork2.ActionInvocation) @bci=525, line=191 (Interpreted frame)
- com.opensymphony.xwork2.DefaultActionInvocation.invoke() @bci=82, line=246 (Compiled frame)
- org.apache.struts2.interceptor.MultiselectInterceptor.intercept(com.opensymphony.xwork2.ActionInvocation) @bci=121, line=73 (Interpreted frame)
- com.opensymphony.xwork2.DefaultActionInvocation.invoke() @bci=82, line=246 (Compiled frame)
com.jd.edmfont.action.EdmBaseInterceptor.intercept(com.opensymphony.xwork2.ActionInvocation) @bci=66, line=47 (Interpreted frame)
- com.opensymphony.xwork2.DefaultActionInvocation.invoke() @bci=82, line=246 (Compiled frame)
- org.apache.struts2.impl.StrutsActionProxy.execute() @bci=20, line=54 (Interpreted frame)
- org.apache.struts2.dispatcher.Dispatcher.serviceAction(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.ServletContext, org.apache.struts2.dispatcher.mapper.ActionMapping) @bci=212, line=546 (Interpreted frame)
- org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.apache.struts2.dispatcher.mapper.ActionMapping) @bci=11, line=77 (Interpreted frame)
org.apache.catalina.connector.CoyoteAdapter.service(org.apache.coyote.Request, org.apache.coyote.Response) @bci=158, line=291 (Interpreted frame)
- org.apache.coyote.http11.Http11Processor.process(java.net.Socket) @bci=514, line=859 (Interpreted frame)
- org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(java.net.Socket) @bci=82, line=602 (Interpreted frame)
- org.apache.tomcat.util.net.JIoEndpoint$Worker.run() @bci=41, line=489 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=662 (Interpreted frame)
Thread 31195: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait() @bci=2, line=485 (Interpreted frame)
- org.apache.tomcat.util.net.JIoEndpoint$Worker.await() @bci=8, line=458 (Interpreted frame)
- org.apache.tomcat.util.net.JIoEndpoint$Worker.run() @bci=11, line=484 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=662 (Interpreted frame)
4.根据堆栈的信息,cpu过高在的线程id,定位到相应的调用
- java.util.regex.Pattern$GroupHead.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=28, line=4168 (Compiled frame; information may be imprecise)
- java.util.regex.Pattern$Loop.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=106, line=4295 (Compiled frame)
- java.util.regex.Pattern$GroupTail.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=70, line=4227 (Compiled frame)
- java.util.regex.Pattern$Ques.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=68, line=3691 (Compiled frame)
- java.util.regex.Pattern$Ques.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=68, line=3691 (Compiled frame)
- java.util.regex.Pattern$Curly.match0(java.util.regex.Matcher, int, int, java.lang.CharSequence) @bci=141, line=3782 (Compiled frame)
- java.util.regex.Pattern$Curly.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=54, line=3744 (Compiled frame)
- java.util.regex.Pattern$GroupHead.match(java.util.regex.Matcher, int, java.lang.CharSequence) @bci=28, line=4168 (Compiled frame)
5.根据定位到的信息可以猜测到应该是正则死循环
6.然后查看代码
String checkemail = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
Pattern regexemail = Pattern.compile(checkemail);
if (mailAddress != null) {
if (!regexemail.matcher(mailAddress).matches()) {
mailAddress = null;
}
}
7.没有循环调用,然后百度google java 正则 死循环 cpu过高
8.sun官网已经有提交的bug,然后得到线上java版本 比较是否是同样问题,根据描述看能否复现
9.发现字符串长度到30左右确实可以复现,接着换成以前检验邮箱的正则,用同样的代码看是否有问题,发现没有问题了,说明是正则的问题
10.仔细检查正则,可以用asm修改Pattern的字节码,增加打印信息,调试,发现假死
public class MethodCallCountTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
try {
if (!"java/util/regex/Pattern$CharProperty".equals(className)
&& !"java/util/regex/Pattern$BmpCharProperty".equals(className)) {
return classfileBuffer;
}
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassAdapter adapter = new MethodCallClassAdapter(writer, className,"match");
ClassReader reader = new ClassReader(classfileBuffer);
reader.accept(adapter, 0);
// 生成新类字节码
return writer.toByteArray();
} catch (Exception e) {
e.printStackTrace();
// 返回旧类字节码
return classfileBuffer;
}
}
public static void premain(String options, Instrumentation ins) {
//注册我自己的字节码转换器
ins.addTransformer(new MethodCallCountTransformer());
}
}
public MethodCallClassAdapter(ClassVisitor classVisitor,String className,String methodName) {
super(classVisitor);
this.className=className;
this.methodName=methodName;
}
// 重写 visitMethod,访问到 "operation" 方法时,
// 给出自定义 MethodVisitor,实际改写方法内容
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature,exceptions);
MethodVisitor wrappedMv = mv;
if (mv != null) {
// 对于 "operation" 方法
if (name.equals(methodName)) {
// 使用自定义 MethodVisitor,实际改写方法内容
wrappedMv = new CountCallMethodAdapter(mv,className,methodName);
}
// else if (name.equals("<init>")) {
// wrappedMv = new ChangeToChildConstructorMethodAdapter(mv,
// className);
// }
}
return wrappedMv;
}
@Override
public void visitCode() {
visitLdcInsn(className);
visitLdcInsn(methodName);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/jd/tuhao/agent/Counter", "printAndIncCount", "(Ljava/lang/String;Ljava/lang/String;)V");
super.visitCode();
}
public class Counter {
private static AtomicInteger methodCallCount = new AtomicInteger(0);
public static void printAndIncCount(String className, String methodName) {
System.out.println(className + "." + methodName + " called, total times " + methodCallCount.incrementAndGet());
}
}
打印信息:
java/util/regex/Pattern$BmpCharProperty.match called, total times 424
java/util/regex/Pattern$CharProperty.match called, total times 425
java/util/regex/Pattern$CharProperty.match called, total times 426
java/util/regex/Pattern$CharProperty.match called, total times 427
java/util/regex/Pattern$CharProperty.match called, total times 428
java/util/regex/Pattern$CharProperty.match called, total times 429
java/util/regex/Pattern$CharProperty.match called, total times 430
java/util/regex/Pattern$CharProperty.match called, total times 431
java/util/regex/Pattern$CharProperty.match called, total times 432
java/util/regex/Pattern$CharProperty.match called, total times 433
java/util/regex/Pattern$CharProperty.match called, total times 434
java/util/regex/Pattern$BmpCharProperty.match called, total times 435
java/util/regex/Pattern$CharProperty.match called, total times 436
java/util/regex/Pattern$BmpCharProperty.match called, total times 437
java/util/regex/Pattern$CharProperty.match called, total times 438
java/util/regex/Pattern$BmpCharProperty.match called, total times 439
java/util/regex/Pattern$CharProperty.match called, total times 440