Wiki

Clone wiki

jtop / CASE01

有一个专门处理任务型的应用发现有停止处理业务逻辑。

通过top看到,系统几个核CPU占用率非常高(100%),且不处理正常业务:

top - 03:07:48 up 232 days,  5:14,  2 users,  load average: 3.77, 3.49, 3.43
Tasks: 127 total,   1 running, 126 sleeping,   0 stopped,   0 zombie
Cpu0  : 10.6%us,  0.3%sy,  0.0%ni, 89.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  :  0.0%us,  0.0%sy,  0.0%ni, 98.7%id,  1.3%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu4  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu5  :  0.0%us,  0.3%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu6  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu7  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:  10485760k total,  9227556k used,  1258204k free,   201184k buffers
Swap:  2097144k total,      116k used,  2097028k free,  1643884k cached

从上面top数据可以看到,有三个核 CPU3,4,6 占用的CPU一直是 100%,那发生了什么事情呢?

接着使用jtop查看,命令如下:

$ java -jar jtop.jar -thread 3 -stack 8 <PID> 2000 100

得到的输出如下:

DefaultQuartzScheduler_Worker-8  TID=86  STATE=RUNNABLE  CPU_TIME=2110 (99.90%)  USER_TIME=2110 (99.90%) Allocted: 0
        java.util.WeakHashMap.put(WeakHashMap.java:405)
        org.aspectj.weaver.Dump.registerNode(Dump.java:253)
        org.aspectj.weaver.World.<init>(World.java:150)
        org.aspectj.weaver.reflect.ReflectionWorld.<init>(ReflectionWorld.java:50)
        org.aspectj.weaver.tools.PointcutParser.setClassLoader(PointcutParser.java:221)
        org.aspectj.weaver.tools.PointcutParser.<init>(PointcutParser.java:207)
        org.aspectj.weaver.tools.PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(PointcutParser.java:128)
        org.springframework.aop.aspectj.AspectJExpressionPointcut.<init>(AspectJExpressionPointcut.java:100)

DefaultQuartzScheduler_Worker-10  TID=88  STATE=RUNNABLE  CPU_TIME=2110 (99.90%)  USER_TIME=2110 (99.90%) Allocted: 0
        java.util.WeakHashMap.put(WeakHashMap.java:405)
        org.aspectj.weaver.Dump.registerNode(Dump.java:253)
        org.aspectj.weaver.World.<init>(World.java:150)
        org.aspectj.weaver.reflect.ReflectionWorld.<init>(ReflectionWorld.java:50)
        org.aspectj.weaver.tools.PointcutParser.setClassLoader(PointcutParser.java:221)
        org.aspectj.weaver.tools.PointcutParser.<init>(PointcutParser.java:183)
        org.aspectj.weaver.reflect.InternalUseOnlyPointcutParser.<init>(InternalUseOnlyPointcutParser.java:22)
        org.aspectj.weaver.reflect.Java15ReflectionBasedReferenceTypeDelegate.getDeclaredPointcuts(Java15ReflectionBasedReferenceTypeDelegate.java:243)

DefaultQuartzScheduler_Worker-6  TID=84  STATE=RUNNABLE  CPU_TIME=2100 (99.43%)  USER_TIME=2100 (99.43%) Allocted: 0
        java.util.WeakHashMap.put(WeakHashMap.java:405)
        org.aspectj.weaver.Dump.registerNode(Dump.java:253)
        org.aspectj.weaver.World.<init>(World.java:150)
        org.aspectj.weaver.reflect.ReflectionWorld.<init>(ReflectionWorld.java:50)
        org.aspectj.weaver.tools.PointcutParser.setClassLoader(PointcutParser.java:221)
        org.aspectj.weaver.tools.PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(PointcutParser.java:129)
        org.springframework.aop.aspectj.AspectJExpressionPointcut.<init>(AspectJExpressionPointcut.java:100)
        org.springframework.aop.aspectj.AspectJExpressionPointcut.<init>(AspectJExpressionPointcut.java:109)

发现这一行java.util.WeakHashMap.put(WeakHashMap.java:405)消耗CPU极高,接近100%, 通过查看JDK源代码,看到:

399.    public V put(K key, V value) {
400.        K k = (K) maskNull(key);
401.        int h = HashMap.hash(k.hashCode());
402.        Entry[] tab = getTable();
403.        int i = indexFor(h, tab.length);
404.
405.        for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
406.            if (h == e.hash && eq(k, e.get())) {
407.                V oldValue = e.value;
408.                if (value != oldValue)
409.                    e.value = value;
410.                return oldValue;
411.            }
412.        }
413.
414.        modCount++;
415.    Entry<K,V> e = tab[i];
416.        tab[i] = new Entry<K,V>(k, value, queue, h, e);
417.        if (++size >= threshold)
418.            resize(tab.length * 2);
419.        return null;
420.    }

从这里我们知道WeakHashMap是线程不安全的,而且这个版本的aspectj没有很好的使用这个类,再通过jstack查看完整的堆栈信息:

   java.lang.Thread.State: RUNNABLE
        at java.util.WeakHashMap.put(WeakHashMap.java:405)
        at org.aspectj.weaver.Dump.registerNode(Dump.java:253)
        at org.aspectj.weaver.World.<init>(World.java:150)
        at org.aspectj.weaver.reflect.ReflectionWorld.<init>(ReflectionWorld.java:50)
        at org.aspectj.weaver.tools.PointcutParser.setClassLoader(PointcutParser.java:221)
        at org.aspectj.weaver.tools.PointcutParser.<init>(PointcutParser.java:183)
        at org.aspectj.weaver.reflect.InternalUseOnlyPointcutParser.<init>(InternalUseOnlyPointcutParser.java:22)
        at org.aspectj.weaver.reflect.Java15ReflectionBasedReferenceTypeDelegate.getDeclaredPointcuts(Java15ReflectionBasedRef
erenceTypeDelegate.java:243)
        at org.aspectj.weaver.ReferenceType.getDeclaredPointcuts(ReferenceType.java:740)
        at org.aspectj.weaver.ResolvedType$7.get(ResolvedType.java:531)
        at org.aspectj.weaver.ResolvedType$7.get(ResolvedType.java:528)
        at org.aspectj.weaver.Iterators$3$1.hasNext(Iterators.java:128)
        at org.aspectj.weaver.Iterators$3.hasNext(Iterators.java:144)
        at org.aspectj.weaver.ResolvedType.findPointcut(ResolvedType.java:539)
        at org.aspectj.weaver.patterns.ReferencePointcut.resolveBindings(ReferencePointcut.java:149)
        at org.aspectj.weaver.patterns.Pointcut.resolve(Pointcut.java:196)
        at org.aspectj.weaver.tools.PointcutParser.resolvePointcutExpression(PointcutParser.java:314)
        at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:295)
        at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:15
9)
        at org.springframework.aop.aspectj.AspectJExpressionPointcut.checkReadyToMatch(AspectJExpressionPointcut.java:149)
        at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:134)
        at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:165)
        at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:225)
        at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:255)
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAut
oProxyCreator.java:73)
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAd
visorAutoProxyCreator.java:57)
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoPro
xyCreator.java:255)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitializa
tion(AbstractAutowireCapableBeanFactory.java:312)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapable
BeanFactory.java:1033)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBean
Factory.java:421)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:264)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:156)
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:640)

知道问题原因那么解决就简单了,原本想通过升级aspectj来解决,但因为一些特殊的历史原因无法简单的通过升级来解决,然后就采用了一种比较简单的解决方案,将调用springgetBean的方法加上了synchronized修饰,问题解决。

Updated