内存泄漏
单例造成的内存泄漏
public class SingletonActivityContext {
private static SingletonActivityContext instance;
private Context context;
private SingletonActivityContext(Context context) {
this.context = context;
}
public static SingletonActivityContext getInstance(Context context) {
if (instance == null) {
instance = new SingletonActivityContext(context);
}
return instance;
}
}
-
问题: 如果传入的是Activity的context,当Activity退出时内存并不会被回收,因为该单例对象持有了Activity的引用。
-
解决:传入Application的context,使单例的生命周期和应用程序的生命周期一样长。
非静态内部类创建静态实例造成的内存泄漏
public class StaticLeakActivity extends Activity {
private static noneStaticClass mResource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (mResource == null) {
mResource = new noneStaticClass();
}
}
private class noneStaticClass {
}
}
-
非静态内部类持有外部类引用,静态(static)实例mResource的生命周期和应用程序一样长,导致静态实例一直持有StaticLeakActivity的引用,导致StaticLeakActivity无法被内存回收。
-
解决:把非静态内部类noneStaticClass改成静态内部类(加static修饰)。
Handler造成内存泄漏
public class HandlerLeakActivity extends Activity {
private final Handler mLeakyHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLeakyHandler.postDelayed(new Runnable() {
@Override
public void run() {
}
}, 1000 * 60 * 10);
finish();
}
/*
* 解决办法:
* 1.将 Handler 声明为静态的
* 2.通过弱引用的方式引入 Activity
*
* */
}
-
Message Queue -> message -> Handler -> Activity.
-
解决:
- 将Handler声明为静态的,这样Handler的生命周期就和Activity无关了。
- 通过弱引用的方式引入Activity。
或者
- onDestroy的时候调用Handler.removeCallbacksAndMessages();
Webview造成的内存泄漏
public class WebviewLeakActivity extends AppCompatActivity {
private WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.wv_show);
mWebView.loadUrl("http://www.baidu.com");
}
@Override
protected void onDestroy() {
destroyWebView();
android.os.Process.killProcess(android.os.Process.myPid());
super.onDestroy();
}
private void destroyWebView() {
if (mWebView != null) {
mWebView.pauseTimers();
mWebView.removeAllViews();
mWebView.destroy();
mWebView = null;
}
}
}
解决: 单独进程
<activity
android:name=".WebviewActivity"
android:process="webview"/>
ReferenceQueue
-
软引用 弱引用
-
对象被垃圾回收,Java虚拟机就会把这个引用加入到与之关联的引用队列中。
源码解析
寻找内存泄漏
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Fresco.initialize(this);
(1)跟进去
LeakCanary.install(this);
}
}
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
(1)跟进去
.buildAndInstall();
}
public RefWatcher buildAndInstall() {
(1)创建RefWatcher对象
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
(2)开启内存泄漏弹窗的Activity。
LeakCanary.enableDisplayLeakActivity(context);
(3)通过ActivityRefWatcher监视Activity的内存泄漏。
(4)跟进去
ActivityRefWatcher.install((Application) context, refWatcher);
}
return refWatcher;
}
(2)开启内存泄漏弹窗的Activity。 的底层调用。
public static void setEnabledBlocking(Context appContext, Class<?> componentClass,
boolean enabled) {
ComponentName component = new ComponentName(appContext, componentClass);
PackageManager packageManager = appContext.getPackageManager();
int newState = enabled ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED;
// Blocks on IPC.
packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP);
}
public final class ActivityRefWatcher {
/** @deprecated Use {@link #install(Application, RefWatcher)}. */
@Deprecated
public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
install(application, refWatcher);
}
public static void install(Application application, RefWatcher refWatcher) {
new ActivityRefWatcher(application, refWatcher).watchActivities();
}
(1)activity生命周期回调
private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
new Application.ActivityLifecycleCallbacks() {
@Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override public void onActivityStarted(Activity activity) {
}
@Override public void onActivityResumed(Activity activity) {
}
@Override public void onActivityPaused(Activity activity) {
}
@Override public void onActivityStopped(Activity activity) {
}
@Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override public void onActivityDestroyed(Activity activity) {
(4)重要
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
};
private final Application application;
private final RefWatcher refWatcher;
/**
* Constructs an {@link ActivityRefWatcher} that will make sure the activities are not leaking
* after they have been destroyed.
*/
public ActivityRefWatcher(Application application, RefWatcher refWatcher) {
this.application = checkNotNull(application, "application");
this.refWatcher = checkNotNull(refWatcher, "refWatcher");
}
void onActivityDestroyed(Activity activity) {
(6)跟进去
refWatcher.watch(activity);
}
(2)注册监听
public void watchActivities() {
// Make sure you don't get installed twice.
stopWatchingActivities();
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
}
(3)解除注册
public void stopWatchingActivities() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
}
}
public final class RefWatcher {
public static final RefWatcher DISABLED = new RefWatcherBuilder<>().build();
(1)执行内存泄漏检测的
private final WatchExecutor watchExecutor;
(2)查询是否在debug调试中,如果再调试中不会执行内存泄漏的检测
private final DebuggerControl debuggerControl;
(3)触发GC垃圾回收
private final GcTrigger gcTrigger;
(4)dump内存的堆文件
private final HeapDumper heapDumper;
(5)持有待检测的和已经内存泄漏的对象的key
private final Set<String> retainedKeys;
(6)创建WeakReference时传入的引用队列,主要是用来判断弱引用持有的对象是否被gc回收,gc回收后会把弱引用添加到队列中
private final ReferenceQueue<Object> queue;
(7)监听产生heap文件的回调
private final HeapDump.Listener heapdumpListener;
(8) 需要排除的一些系统内存泄漏
private final ExcludedRefs excludedRefs;
}
public void watch(Object watchedReference) {
watch(watchedReference, "");
}
/**
* Watches the provided references and checks if it can be GCed. This method is non blocking,
* the check is done on the {@link WatchExecutor} this {@link RefWatcher} has been constructed
* with.
*
* @param referenceName An logical identifier for the watched object.
*/
public void watch(Object watchedReference, String referenceName) {
if (this == DISABLED) {
return;
}
checkNotNull(watchedReference, "watchedReference");
checkNotNull(referenceName, "referenceName");
final long watchStartNanoTime = System.nanoTime();
(1)添加唯一的key值
String key = UUID.randomUUID().toString();
retainedKeys.add(key);
(2)创建弱引用对象
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
(3)检测对象是否回收
ensureGoneAsync(watchStartNanoTime, reference);
}
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
(1)看下watchExecutor实现
watchExecutor.execute(new Retryable() {
@Override public Retryable.Result run() {
(2)跟进去
return ensureGone(reference, watchStartNanoTime);
}
});
}
@Override public void execute(Retryable retryable) {
(3)通过idleHandler执行检测
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
waitForIdle(retryable, 0);
} else {
postWaitForIdle(retryable, 0);
}
}
void postWaitForIdle(final Retryable retryable, final int failedAttempts) {
mainHandler.post(new Runnable() {
@Override public void run() {
waitForIdle(retryable, failedAttempts);
}
});
}
void waitForIdle(final Retryable retryable, final int failedAttempts) {
// This needs to be called from the main thread.
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override public boolean queueIdle() {
postToBackgroundWithDelay(retryable, failedAttempts);
return false;
}
});
}
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
(1)删除已经被回收的弱引用
removeWeaklyReachableReferences();
(2)debug调试中返回
if (debuggerControl.isDebuggerAttached()) {
// The debugger can create false leaks.
return RETRY;
}
(3)已经回收就返回
if (gone(reference)) {
return DONE;
}
(4)主动触发GC
gcTrigger.runGc();
(5)删除已经回收的弱引用
removeWeaklyReachableReferences();
(6)还没被回收就开始分析
if (!gone(reference)) {
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
(7)获取dump快照
File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == RETRY_LATER) {
// Could not dump the heap.
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
(8)开始分析
heapdumpListener.analyze(
new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
gcDurationMs, heapDumpDurationMs));
}
return DONE;
}
总结:
-
通过Application.ActivityLifecycleCallbacks监听Activity的onDestroy方法。
-
当Activity调用onDestroy方法的时候,创建一个弱引用与Activity进行关联。并赋值一个唯一的Key。
-
当Activity被GC的时候,弱引用会被添加到ReferenceQueue。
-
没有添加到队列,手动触发GC,再次检测是否添加到队列。
-
没有,则发生内存泄漏。
分析内存泄漏
public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey) {
long analysisStartNanoTime = System.nanoTime();
if (!heapDumpFile.exists()) {
Exception exception = new IllegalArgumentException("File does not exist: " + heapDumpFile);
return failure(exception, since(analysisStartNanoTime));
}
try {
HprofBuffer buffer = new MemoryMappedFileBuffer(heapDumpFile);
HprofParser parser = new HprofParser(buffer);
(1)接续Hprof文件转换成Snapshot快照
Snapshot snapshot = parser.parse();
(2)去除重复的内存泄漏
deduplicateGcRoots(snapshot);
(3)根据key查询解析结果是否有 我们需要的对象
Instance leakingRef = findLeakingReference(referenceKey, snapshot);
// False alarm, weak reference was cleared in between key check and heap dump.
if (leakingRef == null) {
(4)在heap dump过程中引用被回收
return noLeak(since(analysisStartNanoTime));
}
(5)泄漏的路径
return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef);
} catch (Throwable e) {
return failure(e, since(analysisStartNanoTime));
}
}
private Instance findLeakingReference(String key, Snapshot snapshot) {
(1)从内存快照找查找第一个泄漏的弱引用对象
ClassObj refClass = snapshot.findClass(KeyedWeakReference.class.getName());
List<String> keysFound = new ArrayList<>();
(2)遍历这个对象的所有实例
for (Instance instance : refClass.getInstancesList()) {
List<ClassInstance.FieldValue> values = classInstanceValues(instance);
String keyCandidate = asString(fieldValue(values, "key"));
(3) 如果key值和最开始定义的key值相同,那么返回这个泄漏对象
if (keyCandidate.equals(key)) {
return fieldValue(values, "referent");
}
keysFound.add(keyCandidate);
}
throw new IllegalStateException(
"Could not find weak reference with key " + key + " in " + keysFound);
}
private AnalysisResult findLeakTrace(long analysisStartNanoTime, Snapshot snapshot,
Instance leakingRef) {
ShortestPathFinder pathFinder = new ShortestPathFinder(excludedRefs);
ShortestPathFinder.Result result = pathFinder.findPath(snapshot, leakingRef);
// False alarm, no strong reference path to GC Roots.
if (result.leakingNode == null) {
return noLeak(since(analysisStartNanoTime));
}
LeakTrace leakTrace = buildLeakTrace(result.leakingNode);
String className = leakingRef.getClassObj().getClassName();
// Side effect: computes retained size.
snapshot.computeDominators();
Instance leakingInstance = result.leakingNode.instance;
long retainedSize = leakingInstance.getTotalRetainedSize();
// TODO: check O sources and see what happened to android.graphics.Bitmap.mBuffer
if (SDK_INT <= N_MR1) {
retainedSize += computeIgnoredBitmapRetainedSize(snapshot, leakingInstance);
}
return leakDetected(result.excludingKnownLeaks, className, leakTrace, retainedSize,
since(analysisStartNanoTime));
}
总结:
-
在Snapshot中找到弱引用
-
遍历KeyedWeakReference这个类的所有实例
-
如果key值和最开始定义的key值相同,那么返回这个泄漏对象