19年年末总结一篇《LeakCanary原理从0到1》,当时还比较满意,认为自己就比较了解这个框架了,Too young, Too Simple。

周五群里一个小伙伴问:“线上做内存走漏检测咱Element们有什么思路吗?”。

内存走漏检测首要想到的是 LeakCanary,能够看看能从LeakCanary上找到一些思路吗?

本文并不是从0开始解释 LeakCanary 的作业原理,所认为了阅览体验更佳,还不太了解 LeakCanary监控摄像头多少钱一个javahdxx怎样断定政策内存走漏的读者,能够先从《LeakCanary原理从0到1》开始javascript阅览。

本文将从内存走漏后 LeakCanary 的后续作业开始讲起,剖析 LeakCanary 是怎样找到走漏政策的强引证链的,剖析 LeakCanary 不jvm参数能直接用于线上内存检测的原因,并检验找出线上检测内存走漏的一些思路。

生成Dump文件

在断定java面试题有内存走漏后,「LeakCanary」调用将体系供给的Debug监控摄像头.dumpHprofData(File file)函数,改函数将生成一个虚拟机的内存快照,文件格局为 .happearanceprof,这个dump文件巨细一般有10+M。(本文中所说的dump文件都是指java游戏内存快照的.hprof文件)

//:RefWatcher.java 
Retryable.Result ensureGone(final KeyedWeakReference reference,element滑板 final long watchStart监控摄像头NanoTime)
...
//内部java游戏调用Debug.dumpHprofData(File file)函数
File heapDumpFile = heapDumper.dumpHeap(file);
HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile)
.referenceKey(reference.key)
.buildjvm是什么意思();
heapdumpListener.analyze(heapDump);
....
return DONE;
}

生成dump文件后,LeakCanary 将被走漏政策的 referenceKeydump 文件 政策封装在 HeapDump 政策中,然后交给ServiceHeapDumpListener处理,在ServiceHeapDumpListener中创立 leakcanary 进程并发起服务 HeapAPPAnalyzerService

解析Dump文件

dump 文件的解析作业是jvm内存结构HeapAnalyzerService中完结的,首要逻辑入下:

//HeapAnalyzerService.java
//创立一个剖析器
HeapAnalyzer heapAnalyzer =
new HeapAnalyzer(heapDump.javascriptexcludedR监控摄像头多少钱一个efs, this, heajava面试题pDump.reachabilityInspectorClasses);
//运用剖析器剖析dumpjvm是什么意思文件,得到剖析作用
AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey,
heapDump.computeRetainedHeapSize);
//将剖析作用交由listener组件处理
Aelement滑板bstrac监控眼tAnalysisResultService.sendResultToListener(this, listenerClaselementary什么意思中文sName, heapDump, result);

下面持续跟踪剖析器逻辑,首要检查 HeapAnalyzerchelementanimationeckForLeak 办法:

//: HeapAnalyer.java
public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey,
boolean comp监控别人微信聊天记录uteRetainedSize) {
//读elementary什么意思中文取dump文件,解析文件内容并生成一个Snapshot政策
HprofBuffer buffer = new MemoryMappedFileBuffer(heapDumpFile);
HprofParser parser = new HprofParser(buffer);
Sapproachnapshot snapshot = parserapple.parse();
//消除重复的GcRoots政策
deduplicateGcRoots(snapshot);
//经过applereferenceKey 在Snapshot政策中找到走漏政策
Instance leakingRef = findLeakingReference(refere监控摄像头多少钱一个nceK监控家用长途手机ey, snapshot);
//找到走漏途径
return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, computeRetainedSize);
}

checkForLejvm内存模型ak办法中:

  1. 首要对dump文件的二进制数据进行解析,然后将文件内容信息存放在 Snapshot 政策傍边,这种就能够从Snapshot中取得JVM的内存信息。(关于dump文件格局,有喜爱的能够点击这儿,一起也可去看 square 的 cappearanceom.squareup.haha:haha+,LeakCanary 运用的便是这个 dump 解析库)。
  2. 然后在 Snapsappreciatehot 中类名为 KeyedWeakReferencereferenceKey 所对应的走漏政策 Instence
  3. 毕竟在 Snaapproachpshot 中寻觅走漏政策jvm调优面试题 Instence 的走漏强引证链

查找引证链

走漏政策的引证链式怎样被找到的呢?下app装置下载面持续剖析 findLeakTrelementary什么意思中文ace 办法:

//: HeapAnalyer.jjvm内存模型ava
private AnalysisResult findLeakTrace(long analysisStartNanoTime,java编译器 Snapshot snapshot,
Instance leakingRef, boolean computeRetainedSize) {
//创立最短途径查找器
ShortappleestPathFinder pathFinder = new ShortestPathFinder(excludedRefs);
//运用查找器在sappearnapshot中找到被走漏实例节点
ShortestPathFinder.R监控摄像头软件app下载esult result = pathFinder.findPath(sappstorenapshot, leakingRef);
//运用节点信息结构最短引证链
LeakTrace leakTrace = buildLeakTrace(result.leakingNode);
String classNaJavame = leakelement滑板ingRef.getClassObj().getClassName();
long retainedSize = AnalysisElementResult.RETAINED_HEelementaryAP_SKIPPED;
//将走漏实例的节点信息封装在javascript一个AnalysisResultjvm参数政策中并回来
return lJVMeakDetected(result.excludingKnownLeaks, className, lea监控器什么牌子最好清晰度高kTrace, retainedSize,
since(analysisStartNanoTime));
}

翻开 ShortestPathFinderfindPath 函数,很简单看出其作用便是对每个GcRoot的引证链的堆结构进行BFS遍历,然后将走漏实例地址节点包装在一个 Result监控摄像头 中并回来。

//: ShortestPathFinder.java
Result findPath(Snapshot snapshot, Inst监控器什么牌子最好清晰度高ance leakingjvm内存模型Ref) {
// 将一切的GcRoot节点参与队伍中
enqueuapplicationeGcRoots(snapshot);
LeakNoappointmentde leakingNode = null;
while (!toVisitQueue.isappreciateEmpty() || !toVisitIfNoPathQueue.isEmpty()) {
LeakNode node;
if (!toVisitQueue.isEmpty()) {
node = toVisitQueue.poll();
}
// 找到实例,完毕遍历
if (noapprovede.instance == leakingRef) {
leakingNode = node;
break;
}
//重复检查
if (checkSeen(node)) {
continue;
}
//在visit中将节点与其父节点进jvm内存模型行绑定
if (node.instance instanceof RootObj) {
visitRootObj(nodeapple);
} else if (node.instance instanceof Clajvm废物收回机制ssObj) {
visitClassObj(node);
} else if (napplicationode.instance instanceof ClassInstance) {
visitClassInstance(node);
} else if (node.instance instanceof ArrayInstance) {
visitArrayInstance(nodejavahdxx);
} else {
throw new IllegalStateException("Unexpected typappreciatee for " + node.inappstorestance);
}
}
return new Result(leakingNode, excludingKnownjava怎样读Leakjvm废物收回机制s);
}

接着看监控摄像头,在拿到走漏政策apple节点后怎样创立最短途径引证链呢?

  private LeakTrace buildLeakTrace(LeakNode leakingNode) {
List<LeakTappearraceElement> elements = new Arrayjvm废物收回机制List<>()appreciate;
// We i监控家用长途手机teratejvm废物收回机制 from the leak to the GC root
LeakNode node = new LeakNode(null, null, leakingNode, null);
//从走漏节点开始,自下而上将节点信息逆序参与list傍边
while (node != null) {
LeakTraceElemejava根底知识点nt element = buildLeakElementJVM(node);
if (element != null) {
elements.add(0, element);
}
node = node.parent;
}
List<Reachability> expectedReachability =
computeExpectedReach监控装置流程ability(elements);
return new LeakTrace(elements, expectedReachjvm调优ability);
}

至此,走漏政策的最短引证链已找出appreciate。毕竟程序运用 AnalysisResult政策对最短引证链的信息进行保存并回来。

Listener组件

在剖析的第一步,我们已经看到剖析作用 AnalysisResult 将交由一个 listener 组件处理,这个组件便是 DisplayLeakService ,在 DisplayLeakSe监控体系rvice 中有一段比较要害的代码:

  @Override protected final void onHeapAnalyzed(HeapDump heapDump, AjavascriptnalysisResult result) {
//对dump文件进行重命名
heapDump = renameHeapdump(heapDump);
//将AnalysiselementaryResult政策保存在xxx.hprofelements.result文件中
resultSaved = saveResult(heapDump, result);
...
PendapplicationingIntent = DisJVMplayLeakActivity.createPendingIntent(this, he监控器什么牌子最好清晰度高apDump.referenceKey);
// New notification id every second.
int notificationId = (int) (SysJavatemClock.uptimeMilliappointments() / 1000);
showNotification(this, contentTitle, contentText, pendingIntent, notificationId);
}
private boolean saveResult(HeapDump hjvm内存模型eapDump, AnalysisResult result) {
Fi监控体系le resultFile =element滑板 new File(heapDump.heapDumpFiappearle.getParentFile(),
heapDump.heapDumpFielement什么意思中文le.getName() + ".result");
FileOutputStream fElementos = null;
try {
fos = new FileOutputStream(resultFile);
ObjectOutputStream oojvm参数s = new ObjectOutputStream(fos);
oos.writeObject(heapDump);
oos.writeObject(result);
return true;
} catch (IOException e) {
CanaryLog.d(e, "Could not save leak analyappreciatesis result to disk.");
} finajvm内存结构lly {
if (element什么意思中文fos != null)监控怎样衔接手机 {
try {
fos.close();
} catch (IOException监控家用长途手机 ignored) {
}
}
}
return false;Element
}

在服务组件中,Analysjvm废物收回机制isResult政策被写进了 xxx.hprof.result 文件中。一起服务将闪现一个 Notification,在 Notification 点击后将经过 DisplayLeakelementaryActijava环境变量装备vity 闪现走漏信息。

走漏引证链的闪现

监控器什么牌子最好清晰度高究,看看我们平常看到的 DisplayLeakAc监控tivity 是怎样闪现走漏政策的引证链Java的。(或许看到这儿我们也能才element什么意思中文出来了)

//:DisplayLeakActivity.java
@Overrjvm调优参数ide protapp装置下载ected voijvm是什么意思d onResume(jvm参数) {
super.onResume();
LoadLeaks.load(this, gjvm原理etLeakDirectoryProvider(this));
}

再看看 LoadLeaks#jvm内存结构load();

//: LoadLeaks.java
//LoadLeaks是runnable的子类
static final List<LoadLeaks> inFli监控家用长途手机ght =jvm调优参数 new ArrayList<>();
static final Executor backgrojavascriptundExecutor = njvm调优ewSingleThreadExecutor("LoadLeaks");
static void load(DisplayLeakActijvm参数vity activity, LeakDirectoryProviderapprove leakDirectoryProvider) {
LoadLeaks loadLeaks = new Loadjvm是什么意思Leaks(activity, leakDire监控ctoryProvider);
inFlight.add(loadLeaks);
backjava模拟器groundExecutoJVMr.execute(loadLeaks);
}
@Override public void run() {
final List<Leak> leaks = new ArrayList&java面试题lt;>();
List<File> files = leakDirectoryProvider.listFiles(new Fielement翻译lenameFilter() {
@Override public boolean accept(File dir, String filename) {
return filename.endsWith(".result");
}
});jvm调优面试题
foJavar (File resultFile : files) {
FileInputStreajvm调优面试题m fis = new FileInputapproveStream(resu监控怎样衔接手机ltF监控摄像头ile);
Object监控别人微信聊天记录InputStream ois = new ObjectInputStream(fis);
HeapDump heapDump = (HeapDump) ois.readObject();
AnalysisResult result = (AnalysisResultJVM) ois.rejava编译器adObject();
leaks.add(newelement是什么牌子 Leak(heapDump, result, resultFile));
maielement翻译nHandler.post(new Runnable() {
@Override public void run() {
inFlight.remove(LoadLeaks.tElementhis);
if (actjvm调优面试题ivityOrNull != null) {
activityOrNull.leaks = leaks;
activityOrNull.elementary什么意思中文updateUi();
}
}
});

Displ监控摄像头多少钱一个ayLeakActi监控装置流程vityonResume 办法中,运用线程池读取一切的 xxx.prof.result 文件中的 Analysielement滑板sResult 政策,并运用 haJVMndler#jvm参数postapprove() 在主线程将它们参与到 Activity的成员变量 leaks 中,一起改写 Acti监控器什么牌子最好清晰度高vity 界面。

在点击删去按钮时.hprof文件与.hprof.result文件将被删去;jvm原理

  void deleteVisibleLeak() {
final Leak visibleLeak = gjava编译器etVisibleLeak();
AsyncTask.SERIAL_EXECUTOR.execute(new Runnable() {
@element是什么牌子Override public void run() {
File heapDumpFile = visibleLea监控别人微信聊天记录k.heapDump.heapDumpFile;监控器什么牌子最好清晰度高
File resultFile = visibleLeakjvm内存模型.resultFile;element滑板
boolean resultDeleted = resultFile.delete();
ielementanimationf (!resultDeleted) {
CanaryLog.d("Could not delete result file %s", resultFile.getPath());监控体系
}
boolean heapDumpDelelement什么意思中文eted = heapDum监控眼pFile.delete();
if (!heapDumpDeleted) {
CanaryLog.d("Could not delete heap dump file %s", hjava根底知识点eapDumpFile.getPath());
}
}
});
visibleLeakRefKey = null;
leaks.remove(visibleLeak);
updateUi();
}
void deleteAllLeaks() {
final LeakDirectoryProvider leakDirecappearancetoryProvider = getLeakDirejava面试题ctoryProvider(this);
AsyncTask.SERIAL_EXECUTOR.execute(new Runnable() {
@Override public voiapplicationd run() {
leakDirectoryProvider.clearLeakDirectory();
}
});
leaks = Collections.emptyList();
updateUi();
}

为了抵达较好的闪现作用,闪现时会对引证链傍边的节点信息进行格局上的美化,将字符串拼接成 html 格局闪现, 具体逻辑可检查 DisplayLeakAdapter类。

总结

LeakCanary在断定有内存走漏时,首要会生成一个内存快照文件(.hprof文件),这个快照文件一般有10+M,然后依据element什么意思中文 referenceKey 找出走漏实例,再在快照堆中运用BFS找到实例地址的节点,并以此节监控摄像头点信息反向生成最小引证链。在生成引证链后,将其保存在 AnalysisResjavahdxxult 政策傍边,然后将AnalysisResult政策写入.hporf.result文件,此刻的.hprof.result文件只要几十KB巨细。毕竟,在 DisplayLeakActivityonResume 中读取一切的 .hprjvm调优of.result文件并闪现在界面上。

jvm是什么意思

LeakCanary 直jvm调优接在线上jvm参数运用会有什么样的问题,怎样改善呢?java言语

理解了 LeakCanary 断定政策走漏后所做的作业后elementary什么意思中文就不难知道,直接将 LeakCanary 应用于线上会有如下一些问题:

  1. 每次内存走漏往后,都会生成一个.hprof文件,然后elementtype解析,并将jvm调优面试题作用写入.hprof.result。频频增加,引起手机卡顿等问题。
  2. 相同的走漏问题,会重复生成 .hprof 文件,重复剖析并写入磁盘。
  3. .hprof文件较大,信息回捞成问题。

那应该怎样处理上述问题呢?

  1. 能够依据手机信息来设定一application个内存阈值 M ,当已运用内存小于 M 时,假如此刻有内存走漏,只将走漏政策的信息放入内存傍边保存,不生成.hprof文件。当已运用大于 M 时,生成.hprof文件;当然,也能够判别走漏政策数量大于某个规矩的数值时,生Element成并监控器什么牌子最好清晰度高剖析.hprof文件并剖析,此刻的剖析作用应当包含一个或多个走漏政策引证链的信息。
  2. 当引证链路相一起,依据实际情况看去重。
  3. 不直接回捞.hprof文件,能够挑选回捞.hprof.result文件,或许在本地对.hprof.result进行进一步的整合、去重与优化后再回捞。
  4. 引证链上的信息是稠浊后的,监控眼所以在需要做版别操控并维护稠浊mapping文件做进一步解析java根底知识点

袋鼠水平有限,假如看官们有较好的思路能够在议论中进行评论。文章的缺乏多多包含,希望各位不吝赐教。
其他内存优化上,高级的JVMTI监控政策分配,等我们有实力了再学。jvm调优面试题