網上關於perm區泄露的文章比較少,特別是對於動態類加載方面問題的分析比較少,在此記錄下。html
perm區問題通常兩種解決方案:java
週末早晨收到幾臺機器告警(fullgc告警)(perm大於90%告警),爲快速解決問題,先把幾臺機器重啓解決,留下了一臺禁用端口保留現場進行問題分析。平時上線發版比較頻繁,發版後jvm回收,若是較長時間沒有發版可能會形成泄露,收到告警。python
吃完早飯後登上機器進行排查。git
登入機器,查看內存使用高的進程:github
topweb
pid:15298apache
既然是perm區問題,查看永久代狀況:json
jmap -permstat pid > 15298dump.permstatbootstrap
class_loader classes bytes parent_loader alive? type <bootstrap> 3630 21866152 null live <internal> 0x0000000705e4df00 1 2008 0x00000006c002e450 dead sun/reflect/DelegatingClassLoader@0x00000007c0050c30 0x00000007282e1040 4 23480 0x00000006c002e450 dead com/facebook/swift/codec/internal/compiler/DynamicClassLoader@0x00000007c377f040
經過awk統計type類型,查看加載了哪一種類型的類:swift
awk '{ arr[$6]+=$3 } END { for (key in arr) printf("%s\t%s\n", key, arr[key]) }' 15298dump.permstat | sort -k2,2
ava/net/URLClassLoader@0x00000007c01c1598 0 java/util/ResourceBundle$RBClassLoader@0x00000007c0337380 0 type 0 sun/reflect/DelegatingClassLoader@0x00000007c0050c30 11361872 sun/reflect/misc/MethodUtil@0x00000007c777bf60 134528 <internal> 21866152 com/alibaba/fastjson/util/ASMClassLoader@0x00000007c44de0e0 4785232 N/A 5146 sun/misc/Launcher$AppClassLoader@0x00000007c021c2d8 5423216 com/facebook/swift/codec/internal/compiler/DynamicClassLoader@0x00000007c377f040 5488288 sun/misc/Launcher$ExtClassLoader@0x00000007c01c1978 615216 org/eclipse/jetty/webapp/WebAppClassLoader@0x00000007c06e0da0 738107040
WebAppClassLoader加載最多,達到了738107040,近738m。
知道了加載的類最多,怎麼分析具體加載了哪一種類呢?
以前通常經過Java -verbose查看啓動類加載過程。
對於運行時貌似有兩種方式:
機器上安裝好arthas-boot.jar,並啓動:
java -jar arthas-boot.jar
選擇進程,執行類後臺導出,便後續分析:
classloader -a >> &
打開導出文件:
hash:null, BootstrapClassLoader [B [C [D [F [I [J [Lcom.sun.activation.registries.MimeTypeFile; [Lcom.sun.imageio.plugins.jpeg.DHTMarkerSegment$Htable; [Lcom.sun.imageio.plugins.jpeg.ImageTypeProducer; [Lcom.sun.imageio.plugins.jpeg.JPEGImageReader$CallBackLock$State; [Lcom.sun.imageio.plugins.jpeg.JPEGImageWriter$CallBackLock$State; [Lcom.sun.imageio.plugins.jpeg.SOFMarkerSegment$ComponentSpec; [Lcom.sun.imageio.plugins.jpeg.SOSMarkerSegment$ScanComponentSpec; [Lcom.sun.jmx.mbeanserver.ClassLoaderRepositorySupport$LoaderEntry; [Lcom.sun.jmx.mbeanserver.MXBeanMapping; [Lcom.sun.org.apache.xalan.internal.utils.FeatureManager$Feature; [Lcom.sun.org.apache.xalan.internal.utils.FeaturePropertyBase$State; [Lcom.sun.org.apache.xalan.internal.utils.XMLSecurityManager$Limit; [Lcom.sun.org.apache.xalan.internal.utils.XMLSecurityManager$NameMap; [Lcom.sun.org.apache.xalan.internal.utils.XMLSecurityManager$State; [Lcom.sun.org.apache.xalan.internal.utils.XMLSecurityPropertyManager$Property; [Lcom.sun.org.apache.xerces.internal.impl.XMLEntityManager$CharacterBuffer; [Lcom.sun.org.apache.xerces.internal.impl.dtd.models.CMLeaf; [Lcom.sun.org.apache.xerces.internal.impl.dtd.models.CMNode; [Lcom.sun.org.apache.xerces.internal.impl.dtd.models.CMStateSet; [Lcom.sun.org.apache.xerces.internal.impl.dtd.models.ContentModelValidator; [Lcom.sun.org.apache.xerces.internal.impl.dv.DatatypeValidator; [Lcom.sun.org.apache.xerces.internal.impl.dv.XSSimpleType; [Lcom.sun.org.apache.xerces.internal.impl.dv.xs.AbstractDateTimeDV$DateTimeData; [Lcom.sun.org.apache.xerces.internal.impl.dv.xs.TypeValidator; [Lcom.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl; [Lcom.sun.org.apache.xerces.internal.impl.xpath.regex.RegularExpression; [Lcom.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar; [Lcom.sun.org.apache.xerces.internal.impl.xs.SubstitutionGroupHandler$OneSubGroup; [Lcom.sun.org.apache.xerces.internal.impl.xs.XSAnnotationImpl; [Lcom.sun.org.apache.xerces.internal.impl.xs.XSAttributeUseImpl; [Lcom.sun.org.apache.xerces.internal.impl.xs.XSComplexTypeDecl; [Lcom.sun.org.apache.xerces.internal.impl.xs.XSElementDecl; [Lcom.sun.org.apache.xerces.internal.impl.xs.XSGroupDecl; [Lcom.sun.org.apache.xerces.internal.impl.xs.XSNotationDecl; [Lcom.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl; [Lcom.sun.org.apache.xerces.internal.impl.xs.identity.IdentityConstraint; [Lcom.sun.org.apache.xerces.internal.impl.xs.identity.XPathMatcher; [Lcom.sun.org.apache.xerces.internal.impl.xs.models.XSCMLeaf; [Lcom.sun.org.apache.xerces.internal.impl.xs.models.XSCMValidator; [Lcom.sun.org.apache.xerces.internal.impl.xs.opti.DefaultNode; [Lcom.sun.org.apache.xerces.internal.impl.xs.opti.NodeImpl; [Lcom.sun.org.apache.xerces.internal.impl.xs.traversers.OneAttr; [Lcom.sun.org.apache.xerces.internal.impl.xs.traversers.XSDocumentInfo; [Lcom.sun.org.apache.xerces.internal.impl.xs.util.SimpleLocator; [Lcom.sun.org.apache.xerces.internal.impl.xs.util.XInt; [Lcom.sun.org.apache.xerces.internal.util.Status; [Lcom.sun.org.apache.xerces.internal.util.SymbolHash$Entry; [Lcom.sun.org.apache.xerces.internal.util.SymbolTable$Entry; [Lcom.sun.org.apache.xerces.internal.util.XMLAttributesImpl$Attribute; [Lcom.sun.org.apache.xerces.internal.utils.XMLSecurityManager$Limit; [Lcom.sun.org.apache.xerces.internal.utils.XMLSecurityManager$NameMap; [Lcom.sun.org.apache.xerces.internal.utils.XMLSecurityManager$State; [Lcom.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager$Property; [Lcom.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager$State; [Lcom.sun.org.apache.xerces.internal.xni.QName; [Lcom.sun.org.apache.xerces.internal.xni.XMLLocator; [Lcom.sun.org.apache.xerces.internal.xni.grammars.Grammar; [Lcom.sun.org.apache.xerces.internal.xni.grammars.XSGrammar; [Lcom.sun.org.apache.xerces.internal.xs.ShortList; [Lcom.sun.org.apache.xerces.internal.xs.XSAnnotation; [Lcom.sun.org.apache.xerces.internal.xs.XSAttributeUse; [Lcom.sun.org.apache.xerces.internal.xs.XSComplexTypeDefinition; [Lcom.sun.org.apache.xerces.internal.xs.XSElementDeclaration; [Lcom.sun.org.apache.xerces.internal.xs.XSIDCDefinition; [Lcom.sun.org.apache.xerces.internal.xs.XSModelGroupDefinition; [Lcom.sun.org.apache.xerces.internal.xs.XSNamespaceItem; [Lcom.sun.org.apache.xerces.internal.xs.XSNotationDeclaration; [Lcom.sun.org.apache.xerces.internal.xs.XSObject; [Lcom.sun.org.apache.xerces.internal.xs.XSParticle; [Lcom.sun.org.apache.xerces.internal.xs.XSSimpleTypeDefinition; [Lcom.sun.org.apache.xerces.internal.xs.XSTerm; [Lcom.sun.org.apache.xerces.internal.xs.XSTypeDefinition; [Lcom.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime; [Lcom.sun.org.apache.xml.internal.dtm.DTM; [Lcom.sun.org.apache.xml.internal.dtm.DTMAxisTraverser; [Lcom.sun.org.apache.xml.internal.dtm.DTMIterator; [Lcom.sun.org.apache.xml.internal.dtm.ref.ExpandedNameTable$HashEntry; [Lcom.sun.org.apache.xml.internal.dtm.ref.ExtendedType; [Lcom.sun.org.apache.xpath.internal.Expression; [Lcom.sun.org.apache.xpath.internal.ExpressionNode; [Lcom.sun.org.apache.xpath.internal.XPathVisitable; [Lcom.sun.org.apache.xpath.internal.axes.LocPathIterator; [Lcom.sun.org.apache.xpath.internal.axes.PathComponent; [Lcom.sun.org.apache.xpath.internal.axes.PredicatedNodeTest; [Lcom.sun.org.apache.xpath.internal.axes.SubContextList; [Lcom.sun.org.apache.xpath.internal.objects.XObject; [Lcom.sun.org.apache.xpath.internal.patterns.NodeTest; [Lcom.sun.xml.internal.ws.org.objectweb.asm.Item; [Lcom.sun.xml.internal.ws.org.objectweb.asm.Type; [Ljava.awt.AWTKeyStroke; [Ljava.awt.Dimension; [Ljava.awt.Queue; [Ljava.awt.event.ActionListener; [Ljava.awt.event.ComponentListener; [Ljava.awt.event.FocusListener; [Ljava.awt.event.HierarchyBoundsListener; ......
統計最多的類:
#!/usr/bin/python from collections import Counter package_name_count_dic = {} for s in open('14.txt'): full_qualified_name = s.strip() if not full_qualified_name: continue class_name_index = full_qualified_name.rfind('.') if class_name_index >= 0: package_name, class_name = full_qualified_name[:class_name_index], full_qualified_name[class_name_index + 1:] else: package_name = class_name = full_qualified_name if package_name in package_name_count_dic: package_name_count_dic[package_name] += 1 else: package_name_count_dic[package_name] = 1 k = Counter(package_name_count_dic) high = k.most_common(5) for p, c in high: print p, c
最多的幾個類:
真兇:ma.glasnost.orika.generated。
查看代碼中誰使用了orika類庫。
發現是閃購同窗,因爲咱們的系統目前對接多方,閃購同窗還在咱們系統作代碼開發,在codereview上存在一些問題。
@Component public class SGMapperFactory implements FactoryBean<MapperFactory> { @Override public MapperFactory getObject() { return new DefaultMapperFactory.Builder().build(); } @Override public Class<?> getObjectType() { return MapperFactory.class; } @Override public boolean isSingleton() { return true; } }
每次調用getObject
都會新建立DefaultMapperFactory對象。MapperGenerator 每次會動態產生類。
至此問題排查,推進閃購同窗改動。
看代碼是3月份代碼寫的,爲什麼到如今才發現問題呢?
首先是平時發版比較頻繁,jvm發版後問題解決。 最近發版比較少,同時這些是擴容機器,在最近的幾回發版中並無發版,因此形成類加載持續一段時間,最後形成永久代泄露。 爲儘早發現問題須要在流程上進行控制,好比增長codereview細緻程度,在灰度發版後對發版機器進行引流壓測,儘早發現問題,解決問題。