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