MAT JDK下载地址
链接:https://pan.baidu.com/s/13ESnQDksLYA15GQh8_JldQ
提取码:jhhp
工具mat. eclipse memory analyzer
1.转换为标准hprof
hprof-conv -z in. hprof out.hprof //hprof-conv sdk下面的工具
2. mat打开out.hprof
3.查看Leak Suspects,大概是泄露在哪里,不过一般没什么价值
4.点击histogram图标(左边第二个图标)
5.查看那种最多,比如app一般搜索PhoneWindow,可以看到有多少泄露。假如很多的话就证明就是这里发生内存泄露,
6.选择右键list objects-- with incoming reference,会看到这些窗口是来至于哪里
7.选择右键path to gc roots -- exclude all platform/ weak/ soft etc references 看到gc过程可以看到是什么对象没有回收导致泄露
8.使用OQL ( open object query language)
查询对象泄露的个数,比如
select * from com. android. settings. Settings$NetworkDashboardActivity,上面有个感叹号图标执行搜索F5
实例
AccessibilityStateChangeListener内存泄露例子,在hprof文件中发现了300个此对象,这是不应该的。此对象是在ViewRootImpl初始化时add,在doDie时remove,这里泄露的话,原因就是为啥doDie没执行或者没执行最后的remove。查看log是因为没有成对的执行dispatchDetachedFromWindow,原因是mAdded为false
//AccessibilityStateChangeListener内存泄露例子
public ViewRootImpl(Context context, Display display) {
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager, mHandler);
mHighContrastTextManager = new HighContrastTextManager();
mAccessibilityManager.addHighTextContrastStateChangeListener(
mHighContrastTextManager, mHandler);
mAdded = false;
}
@/frameworks/base/core/java/android/view/accessibility/AccessibilityManager.java
public void addAccessibilityStateChangeListener(
@NonNull AccessibilityStateChangeListener listener, @Nullable Handler handler) {
synchronized (mLock) {
mAccessibilityStateChangeListeners
.put(listener, (handler == null) ? mHandler : handler);
}
}
//removeAccessibilityStateChangeListener
void dispatchDetachedFromWindow() {
mAccessibilityManager.removeAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
mAccessibilityManager.removeHighTextContrastStateChangeListener(
mHighContrastTextManager);
removeSendWindowContentChangedCallback();
}
void doDie() {
checkThread();
if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
synchronized (this) {
if (mRemoved) {
return;
}
mRemoved = true;
if (mAdded) {
dispatchDetachedFromWindow();
}
mAdded = false;
}
WindowManagerGlobal.getInstance().doRemoveView(this);
}
mAdded是因为发生了异常导致mAdded未false,就不能remove对象,就造成泄露
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
mAdded = true;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
mAdded = false;
switch (res) {
case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
throw new WindowManager.BadTokenException(
"Unable to add window -- token " + attrs.token
+ " is not valid; is your activity running?");
}
throw new RuntimeException(
"Unable to add window -- unknown error code " + res);
}
}
}
}