简介 OOM
对于Android 开发会经常遇到一个词,就是OOM,也就是 Out Of Memory 的首字母简写。
出现这个异常的原因,也可想而知了。系统提供的内存有限,而程序想要的很多,超出了系统所能提供的大小,就出现了此异常。
举个栗子
下面举一个经典的例子:
public class SecondActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//模拟内存泄漏
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
Log.d("hahha", "leak");
}
}, 10000L);
}
}
这个例子是创建了 Handler,持有了 Activity,当 Activity被销毁的时候,就会发生内存溢出。
我们除了能够通过 logcat 观察日志,发现出现这个异常之外,还可以在看看看 LeakCanray。
LeakCanray
LeakCanary 是 Square 公司开发的一款内存泄漏自动探测神器!
github网址是:https://github.com/square/leakcanary
下面看看如何集成:
使用 Android Studio 的小伙伴可以在 build.gradle 中添加:
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
}
这样 debug 和 release 的两种情况下都集成了。
在个人的项目的 application 中:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
当项目中出现内存溢出的时候 会在日志中出现类似这样的内容:
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: In com.wj.leakcanary:1.0:1.
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * com.wj.leakcanary.SecondActivity has leaked:
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * GC ROOT static android.os.Looper.sMainLooper
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * references android.os.Looper.mQueue
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * references android.os.MessageQueue.mMessages
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * references android.os.Message.callback
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * references com.wj.leakcanary.SecondActivity$1.this$0 (anonymous implementation of java.lang.Runnable)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * leaks com.wj.leakcanary.SecondActivity instance
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Retaining: 29 KB.
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Reference Key: 8a80f4a6-d838-4188-b6b5-6ef26bb623c6
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Device: Genymotion generic Samsung Galaxy Note 2 - 4.3 - API 18 - 720x1280 vbox86p
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Android Version: 4.3 API: 18 LeakCanary: 1.4 6b04880
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Durations: watch=5034ms, gc=105ms, heap dump=234ms, analysis=8657ms
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Details:
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Class android.os.Looper
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static $staticOverhead = byte[72]@2764904665 (0xa4cd18d9)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static TAG = java.lang.String@2764904904 (0xa4cd19c8)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static sThreadLocal = java.lang.ThreadLocal@2765076760 (0xa4cfb918)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static sMainLooper = android.os.Looper@2766952392 (0xa4ec57c8)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Instance of android.os.Looper
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static $staticOverhead = byte[72]@2764904665 (0xa4cd18d9)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static TAG = java.lang.String@2764904904 (0xa4cd19c8)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static sThreadLocal = java.lang.ThreadLocal@2765076760 (0xa4cfb918)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static sMainLooper = android.os.Looper@2766952392 (0xa4ec57c8)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mLogging = null
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mQueue = android.os.MessageQueue@2766952424 (0xa4ec57e8)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mThread = java.lang.Thread@2764219520 (0xa4c2a480)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mRun = true
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Instance of android.os.MessageQueue
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mPendingIdleHandlers = android.os.MessageQueue$IdleHandler[4]@2766969784 (0xa4ec9bb8)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mIdleHandlers = java.util.ArrayList@2766952512 (0xa4ec5840)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mMessages = android.os.Message@2767445304 (0xa4f3dd38)
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mNextBarrierToken = 12
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mBlocked = true
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mPtr = -1185325408
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mQuitAllowed = false
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | mQuiting = false
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: * Instance of android.os.Message
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static FLAG_IN_USE = 1
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static FLAGS_TO_CLEAR_ON_COPY_FROM = 1
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static FLAG_ASYNCHRONOUS = 2
12-26 04:26:38.505 19038-19383/com.wj.leakcanary D/LeakCanary: | static sPoolSize = 4
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | static MAX_POOL_SIZE = 50
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | static $staticOverhead = byte[192]@2765071577 (0xa4cfa4d9)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | static sPoolSync = java.lang.Object@2765094600 (0xa4cffec8)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | static sPool = android.os.Message@2766957048 (0xa4ec69f8)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | static CREATOR = android.os.Message$1@2765082744 (0xa4cfd078)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | target = android.os.Handler@2767087960 (0xa4ee6958)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | replyTo = null
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | callback = com.wj.leakcanary.SecondActivity$1@2766935080 (0xa4ec1428)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | data = null
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | obj = null
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | next = null
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | when = 4781012
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | arg2 = 0
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | arg1 = 0
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | what = 0
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | flags = 0
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: * Instance of com.wj.leakcanary.SecondActivity$1
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | this$0 = com.wj.leakcanary.SecondActivity@2767040224 (0xa4edaee0)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: * Instance of com.wj.leakcanary.SecondActivity
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | mActionBar = null
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | mActivityInfo = android.content.pm.ActivityInfo@2767272368 (0xa4f139b0)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | mAllLoaderManagers = java.util.HashMap@2767242480 (0xa4f0c4f0)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | mApplication = com.wj.leakcanary.MyApplication@2766975648 (0xa4ecb2a0)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | mWindowManager = android.view.WindowManagerImpl@2767030416 (0xa4ed8890)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | mWindow = com.android.internal.policy.impl.PhoneWindow@2767033512 (0xa4ed94a8)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | mUiThread = java.lang.Thread@2764219520 (0xa4c2a480)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | mComponent = android.content.ComponentName@2766959600 (0xa4ec73f0)
12-26 04:26:38.509 19038-19383/com.wj.leakcanary D/LeakCanary: | mToken = android.os.BinderProxy@2766959736 (0xa4ec7478)
后面还有好些日志,就不粘贴了。
在手机上安装了项目之后,会有一个 logo
点进去之后,可以快速查看出现异常的信息等。方便,效率高。