commit | 1f151c447e9d283e0c28973e922549ba38a590b6 | [log] [tgz] |
---|---|---|
author | Pierre-Yves Ricau <py@squareup.com> | Tue May 21 16:51:27 2019 |
committer | Pierre-Yves Ricau <py@squareup.com> | Tue May 21 16:51:27 2019 |
tree | e838068d54896edfc2b5ae952c7821fdee6ac360 | |
parent | 056ef682311691a20027edf29dbbb2d5cc119742 [diff] |
Prepare 2.0-alpha-2 release
🐤 A memory leak detection library for Android.
“A small leak will sink a great ship.” - Benjamin Franklin
Add LeakCanary to build.gradle
:
dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-2' }
That's it, there is no code change needed! LeakCanary will automatically show a notification when a memory leak is detected in debug builds.
What's next?
Note: LeakCanary 2 is in alpha.
In a Java based runtime, a memory leak is a programming error that causes an application to keep a reference to an object that is no longer needed. As a result, the memory allocated for that object cannot be reclaimed, eventually leading to an OutOfMemoryError crash.
For example, an Android activity instance is no longer needed after its onDestroy()
method is called, and storing a reference to that activity in a static field would prevent it from being garbage collected.
Memory leaks are very common in Android apps. OutOfMemoryError (OOM) is the top crash for most apps on the play store, however that‘s usually not counted correctly. When memory is low the OOM can be thrown from anywhere in your code, which means every OOM has a different stacktrace and they’re counted as different crashes.
When we first enabled LeakCanary in the Square Point Of Sale app, we were able to find and fix several leaks and reduced the OutOfMemoryError crash rate by 94%.
.hprof
file stored on the file system. The default threshold is 5 retained instances when the app is visible, 1 otherwise..hprof
file and finds the chain of references that prevents retained instances from being garbage collected (leak trace). A leak trace is technically the shortest strong reference path from GC Roots to retained instances, but that's a mouthful.To fix a memory leak, you need to look at the sub chain of possible leak causes and find which reference is causing the leak, i.e. which reference should have been cleared at the time of the leak. LeakCanary highlights with a red underline wave the references that are the possible causes of the leak.
If you cannot figure out a leak, please do not file an issue. Instead, create a Stack Overflow question using the leakcanary tag.
If you think a recipe might be missing or you‘re not sure that what you’re trying to achieve is possible with the current APIs, please file an issue. Your feedback help us make LeakCanary better for the entire community.
LeakCanary is released as two distinct libraries: com.squareup.leakcanary:leaksentry
and com.squareup.leakcanary:leakcanary-android
which depends on leaksentry
.
LeakSentry is in charge of detecting retained instances. Its configuration can be updated at any time by replacing LeakSentry.config
:
class DebugExampleApplication : ExampleApplication() { override fun onCreate() { super.onCreate() LeakSentry.config = LeakSentry.config.copy(watchFragmentViews = false) } }
LeakCanary is in charge of dumping the heap and analyzing it. Its configuration can be updated at any time by replacing LeakCanary.config
:
disableLeakCanaryButton.setOnClickListener { LeakCanary.config = LeakCanary.config.copy(dumpHeap = false) }
In your application, you may have other objects with a lifecycle, such as fragments, services, Dagger components, etc. Use LeakSentry.refWatcher
to watch instances that should be garbage collected:
class MyService : Service { // ... override fun onDestroy() { super.onDestroy() LeakSentry.refWatcher.watch(this) } }
com.squareup.leakcanary:leakcanary-android
should only be used in debug builds. It depends on com.squareup.leakcanary:leaksentry
which you can use in production to track and count retained instances.
In your build.gradle
:
dependencies { implementation 'com.squareup.leakcanary:leaksentry:2.0-alpha-2' }
In your leak reporting code:
val retainedInstanceCount = LeakSentry.refWatcher.retainedKeys.size
Add the leakcanary-android-instrumentation
dependency to your instrumentation tests:
androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:${leakCanaryVersion}"
Add the dedicated run listener to defaultConfig
in your build.gradle
:
android { defaultConfig { // ... testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArgument "listener", "com.squareup.leakcanary.FailTestOnLeakRunListener" } }
Run the instrumentation tests:
./gradlew leakcanary-sample:connectedCheck
You can extend FailTestOnLeakRunListener
to customize the behavior.
The activity that displays leaks comes with a default icon and label, which you can change by providing R.mipmap.leak_canary_icon
and R.string.leak_canary_display_activity_label
in your app:
res/ mipmap-hdpi/ leak_canary_icon.png mipmap-mdpi/ leak_canary_icon.png mipmap-xhdpi/ leak_canary_icon.png mipmap-xxhdpi/ leak_canary_icon.png mipmap-xxxhdpi/ leak_canary_icon.png mipmap-anydpi-v26/ leak_canary_icon.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="leak_canary_display_activity_label">MyLeaks</string> </resources>
You can change the default behavior to upload the leak trace and heap dump to a server of your choosing.
TODO Document this
TODO Document this
TODO Document this
Yes. There are a number of known memory leaks that have been fixed over time in AOSP as well as in manufacturer implementations. When such a leak occurs, there is little you can do as an app developer to fix it. For that reason, LeakCanary has a built-in list of known Android leaks to ignore: AndroidExcludedRefs.kt.
If you find a new one, please create an issue and follow these steps:
AndroidExcludedRefs.kt
. Optional: if you find a hack to clear that leak on previous versions of Android, feel free to document it.Sometimes the leak trace isn't enough and you need to dig into a heap dump with MAT or YourKit.
Here's how you can find the leaking instance in the heap dump:
leakcanary.KeyedWeakReference
key
field.KeyedWeakReference
that has a key
field equal to the reference key reported by LeakCanary.referent
field of that KeyedWeakReference
is your leaking object.0. LeakCanary is a debug only library.
Update your dependencies to the latest SNAPSHOT (see build.gradle):
dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-2-SNAPSHOT' }
Add Sonatype's snapshots
repository:
repositories { mavenCentral() maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } }
LeakCanary was created and open sourced by @pyricau, with many contributions from the community.
The name LeakCanary is a reference to the expression canary in a coal mine, because LeakCanary is a sentinel used to detect risks by providing advance warning of a danger. Props to @edenman for suggesting it!
Your presentation should be here, please update this list! Any technical level welcome.
Your article should be here, please update this list! Any technical level welcome.
Copyright 2015 Square, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.