3. Activity的泄漏
StrictMode对于Activity的泄漏检测也是有的。
泄漏的日志:
D/StrictMode: StrictMode policy violation: android.os.strictmode.InstanceCountViolation: class com.ifreedomer.strictmode.activity.TestLeakedActivity; instances=3; limit=1
at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)
StrictMode的activity泄漏检测,用的是引用计数法,大致思路分为三步:
- 使用map存储Activity的类与计数Map<Class,Count>
StrictMode.java
private static final HashMap<Class, Integer> sExpectedActivityInstanceCount = new HashMap<>();
- 在Activity启动阶段增加计数
ActivityThread.java
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
StrictMode.incrementExpectedActivityCount(activity.getClass());
}
- 在Activity的回收阶段减少计数
ActivityThread.java
/** Core implementation of activity destroy call. */
void performDestroyActivity(ActivityClientRecord r, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
StrictMode.decrementExpectedActivityCount(activityClass);
}
3.1 增加计数实现
- 是否开启了检测开关
- 是否有计数,如果有+1
- 放回map
public static void incrementExpectedActivityCount(Class klass) {
if (klass == null) {
return;
}
synchronized (StrictMode.class) {
if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
return;
}
// Use the instance count from InstanceTracker as initial value.
Integer expected = sExpectedActivityInstanceCount.get(klass);
Integer newExpected =
expected == null ? InstanceTracker.getInstanceCount(klass) + 1 : expected + 1;
sExpectedActivityInstanceCount.put(klass, newExpected);
}
}
3.2 减少计数实现
- 是否开启了检测开关
- 是否有计数,如果有-1
- GC
- 重新寻找是否有引用,有几个引用
- 引用大于计数,则认为有泄漏
public static void decrementExpectedActivityCount(Class klass) {
if (klass == null) {
return;
}
final int limit;
synchronized (StrictMode.class) {
if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
return;
}
Integer expected = sExpectedActivityInstanceCount.get(klass);
int newExpected = (expected == null || expected == 0) ? 0 : expected - 1;
if (newExpected == 0) {
sExpectedActivityInstanceCount.remove(klass);
} else {
sExpectedActivityInstanceCount.put(klass, newExpected);
}
// Note: adding 1 here to give some breathing room during
// orientation changes. (shouldn't be necessary, though?)
limit = newExpected + 1;
}
// Quick check.
int actual = InstanceTracker.getInstanceCount(klass);
if (actual <= limit) {
return;
}
System.gc();
System.runFinalization();
System.gc();
//计算有几个引用
long instances = VMDebug.countInstancesOfClass(klass, false);
if (instances > limit) {
onVmPolicyViolation(new InstanceCountViolation(klass, instances, limit));
}
}