Почему LeakCanary сообщает об утечке поля каждой активности даже сразу после ее запуска?

Например, у меня есть следующий код для пользовательского класса приложения (чтобы «активировать» LeakCanary внутри проекта)

public class MyApp extends Application {

    private RefWatcher refWatcher;
    @Override

    public void onCreate() {
        super.onCreate();

        if (LeakCanary.isInAnalyzerProcess(this)) {
            // This process is dedicated to LeakCanary for heap analysis.
            // You should not init your app in this process.
            return;
        }
        refWatcher = LeakCanary.install(this);
    }

    public void watch(Object o) {
        refWatcher.watch(o);
    }
}

И у меня есть следующая деятельность:

public class LeakActivity extends AppCompatActivity {

    private String str;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_memory_leak);

        str = "Pam Pam";
        ((MyApp)getApplication()).watch(str);
    }
}

Каждый раз, когда активность запускается или воссоздается после изменения конфигурации (поворот экрана), я вижу уведомление от LeakCanary о том, что произошла утечка 'str'

Could not dump heap, previous analysis still is in progress.
In com.daxh.explore.myapp:0.3:3.
* java.lang.String has leaked:
* GC ROOT static android.app.ActivityThread.sCurrentActivityThread
* references android.app.ActivityThread.mActivities
* references android.util.ArrayMap.mArray
* references array java.lang.Object[].[3]
* references android.app.ActivityThread$ActivtyClientRecord.activity
* references com.daxh.explore.myapp.activities.LeakActivity.str
* leaks java.lang.String instance
* Retaining: 38B.
* Reference Key: 9967ddcf-b2bf-4e9f-8f3e-ef007931f9b2
* Device: unknown Android Android SDK built for x86_64 sdk_google_phone_x86_64
1.5 00f37f5
* Durations: watch=5325ms, gc=110ms, heap dump=381ms, analysis=4286ms
* Details:
* Class android.app.ActivityThread
|   static SERVICE_DONE_EXECUTING_STOP = 2
|   static THUMBNAIL_FORMAT = android.graphics.Bitmap$Config@1887272032 (0x707d7c60)
|   static MIN_TIME_BETWEEN_GCS = 5000
|   static DEBUG_SERVICE = false
|   static DEBUG_PROVIDER = false
|   static sMainThreadHandler = android.app.ActivityThread$H@314965280 (0x12c5fd20)
|   static sCurrentBroadcastIntent = java.lang.ThreadLocal@1948209872 (0x741f52d0)
|   static PATTERN_SEMICOLON = java.util.regex.Pattern@1948519600 (0x74240cb0)
|   static sPackageManager = android.content.pm.IPackageManager$Stub$Proxy@314982592 (0x12c640c0)
|   static DEBUG_CONFIGURATION = false
|   static DEBUG_BROADCAST = false
|   static SERVICE_DONE_EXECUTING_START = 1
|   static DEBUG_MESSAGES = false
|   static DEBUG_BACKUP = false
|   static TAG = java.lang.String@1879056976 (0x70002250)
|   static SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003
|   static HEAP_FULL_COLUMN = java.lang.String@1879025368 (0x6fffa6d8)
|   static $staticOverhead = byte[208]@1888712369 (0x709376b1)
|   static LOG_ON_PAUSE_CALLED = 30021
|   static SERVICE_DONE_EXECUTING_ANON = 0
|   static sCurrentActivityThread = android.app.ActivityThread@314790144 (0x12c35100)
|   static LOG_ON_RESUME_CALLED = 30022
|   static ACTIVITY_THREAD_CHECKIN_VERSION = 3
|   static DEBUG_RESULTS = false
|   static HEAP_COLUMN = java.lang.String@1879025344 (0x6fffa6c0)
|   static localLOGV = false
|   static DEBUG_MEMORY_TRIM = false
* Instance of android.app.ActivityThread
|   static SERVICE_DONE_EXECUTING_STOP = 2
|   static THUMBNAIL_FORMAT = android.graphics.Bitmap$Config@1887272032 (0x707d7c60)
|   static MIN_TIME_BETWEEN_GCS = 5000
|   static DEBUG_SERVICE = false
|   static DEBUG_PROVIDER = false
|   static sMainThreadHandler = android.app.ActivityThread$H@314965280 (0x12c5fd20)
|   static sCurrentBroadcastIntent = java.lang.ThreadLocal@1948209872 (0x741f52d0)
|   static PATTERN_SEMICOLON = java.util.regex.Pattern@1948519600 (0x74240cb0)
|   static sPackageManager = android.content.pm.IPackageManager$Stub$Proxy@314982592 (0x12c640c0)
|   static DEBUG_CONFIGURATION = false
|   static DEBUG_BROADCAST = false
|   static SERVICE_DONE_EXECUTING_START = 1
|   static DEBUG_MESSAGES = false
|   static DEBUG_BACKUP = false
|   static TAG = java.lang.String@1879056976 (0x70002250)
|   static SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003
|   static HEAP_FULL_COLUMN = java.lang.String@1879025368 (0x6fffa6d8)
|   static $staticOverhead = byte[208]@1888712369 (0x709376b1)
|   static LOG_ON_PAUSE_CALLED = 30021
|   static SERVICE_DONE_EXECUTING_ANON = 0
|   static sCurrentActivityThread = android.app.ActivityThread@314790144 (0x12c35100)
|   static LOG_ON_RESUME_CALLED = 30022
|   static ACTIVITY_THREAD_CHECKIN_VERSION = 3
|   static DEBUG_RESULTS = false
|   static HEAP_COLUMN = java.lang.String@1879025344 (0x6fffa6c0)
|   static localLOGV = false
|   static DEBUG_MEMORY_TRIM = false
|   mActivities = android.util.ArrayMap@314965312 (0x12c5fd40)
|   mAllApplications = java.util.ArrayList@314965376 (0x12c5fd80)
|   mAppThread = android.app.ActivityThread$ApplicationThread@314965248 (0x12c5fd00)
|   mAvailThumbnailBitmap = null
|   mBackupAgents = android.util.ArrayMap@314965408 (0x12c5fda0)
|   mBoundApplication = android.app.ActivityThread$AppBindData@315023456 (0x12c6e060)
|   mCompatConfiguration = android.content.res.Configuration@314730336 (0x12c26760)
|   mConfiguration = android.content.res.Configuration@314730240 (0x12c26700)
|   mCoreSettings = android.os.Bundle@314975552 (0x12c62540)
|   mCurDefaultDisplayDpi = 560
|   mDensityCompatMode = false
|   mGcIdler = android.app.ActivityThread$GcIdler@314734688 (0x12c27860)
|   mGcIdlerScheduled = false
|   mH = android.app.ActivityThread$H@314965280 (0x12c5fd20)
|   mInitialApplication = com.daxh.explore.myapp.MyAppApp@315135744 (0x12c89700)
|   mInstrumentation = android.app.Instrumentation@314896144 (0x12c4ef10)
|   mInstrumentationAppDir = null
|   mInstrumentationLibDir = null
|   mInstrumentationPackageName = null
|   mInstrumentationSplitAppDirs = null
|   mInstrumentedAppDir = null
|   mInstrumentedLibDir = null
|   mInstrumentedSplitAppDirs = null
|   mJitEnabled = true
|   mLocalProviders = android.util.ArrayMap@314965600 (0x12c5fe60)
|   mLocalProvidersByName = android.util.ArrayMap@314965632 (0x12c5fe80)
|   mLooper = android.os.Looper@314965184 (0x12c5fcc0)
|   mMainThreadConfig = android.content.res.Configuration@314730048 (0x12c26640)
|   mNewActivities = null
|   mNumVisibleActivities = 1
|   mOnPauseListeners = android.util.ArrayMap@314965664 (0x12c5fea0)
|   mPackages = android.util.ArrayMap@314965440 (0x12c5fdc0)
|   mPendingConfiguration = null
|   mProfiler = android.app.ActivityThread$Profiler@315122720 (0x12c86420)
|   mProviderMap = android.util.ArrayMap@314965536 (0x12c5fe20)
|   mProviderRefCountMap = android.util.ArrayMap@314965568 (0x12c5fe40)
|   mRelaunchingActivities = java.util.ArrayList@314965504 (0x12c5fe00)
|   mResourcePackages = android.util.ArrayMap@314965472 (0x12c5fde0)
|   mResourcesManager = android.app.ResourcesManager@314965696 (0x12c5fec0)
|   mServices = android.util.ArrayMap@314965344 (0x12c5fd60)
|   mSomeActivitiesChanged = true
|   mSystemContext = android.app.ContextImpl@315125888 (0x12c87080)
|   mSystemThread = false
|   mThumbnailCanvas = null
|   mThumbnailHeight = -1
|   mThumbnailWidth = -1
* Instance of android.util.ArrayMap
|   static EMPTY = android.util.ArrayMap@1887219864 (0x707cb098)
|   static BASE_SIZE = 4
|   static DEBUG = false
|   static EMPTY_IMMUTABLE_INTS = int[0]@1887206984 (0x707c7e48)
|   static mBaseCacheSize = 0
|   static CACHE_SIZE = 10
|   static mBaseCache = null
|   static mTwiceBaseCacheSize = 1
|   static mTwiceBaseCache = java.lang.Object[16]@316499536 (0x12dd6650)
|   static $staticOverhead = byte[80]@1888643129 (0x70926839)
|   static TAG = java.lang.String@1879059712 (0x70002d00)
|   mArray = java.lang.Object[8]@315835968 (0x12d34640)
|   mCollections = null
|   mHashes = int[4]@315628768 (0x12d01ce0)
|   mSize = 2
* Array of java.lang.Object[]
|   [0] = android.os.BinderProxy@315011488 (0x12c6b1a0)
|   [1] = android.app.ActivityThread$ActivityClientRecord@314589568 (0x12c04180)
|   [2] = android.os.BinderProxy@317075616 (0x12e630a0)
|   [3] = android.app.ActivityThread$ActivityClientRecord@317288320 (0x12e96f80)
|   [4] = null
|   [5] = null
|   [6] = null
|   [7] = null
* Instance of android.app.ActivityThread$ActivityClientRecord
|   activity = com.daxh.explore.myapp.activities.LeakActivity@315971680 (0x12d55860)
|   activityInfo = android.content.pm.ActivityInfo@317288192 (0x12e96f00)
|   compatInfo = android.content.res.CompatibilityInfo@317076768 (0x12e63520)
|   createdConfig = null
|   embeddedID = null
|   hideForNow = false
|   ident = 958616894
|   intent = android.content.Intent@316506176 (0x12dd8040)
|   isForward = true
|   lastNonConfigurationInstances = null
|   mPendingRemoveWindow = null
|   mPendingRemoveWindowManager = null
|   newConfig = null
|   nextIdle = null
|   onlyLocalRequest = false
|   packageInfo = android.app.LoadedApk@314593792 (0x12c05200)
|   parent = null
|   paused = false
|   pendingConfigChanges = 0
|   pendingIntents = null
|   pendingResults = null
|   persistentState = null
|   profilerInfo = null
|   referrer = java.lang.String@317076800 (0x12e63540)
|   startsNotResumed = false
|   state = null
|   stopped = false
|   token = android.os.BinderProxy@317075616 (0x12e630a0)
|   voiceInteractor = null
|   window = com.android.internal.policy.impl.PhoneWindow@315859200 (0x12d3a100)
* Instance of com.daxh.explore.myapp.activities.LeakActivity
|   str = java.lang.String@316651872 (0x12dfb960)
|   mDelegate = android.support.v7.app.AppCompatDelegateImplV14@314801856 (0x12c37ec0)
|   mEatKeyUpEvent = false
|   mResources = null
|   mThemeId = 2131230884
|   mCreated = true
|   mFragments = android.support.v4.app.FragmentController@316866960 (0x12e30190)
|   mHandler = android.support.v4.app.FragmentActivity$1@317088416 (0x12e662a0)
|   mNextCandidateRequestIndex = 0
|   mOptionsMenuInvalidated = false
|   mPendingFragmentActivityResults = android.support.v4.util.SparseArrayCompat@317092160 (0x12e67140)
|   mReallyStopped = false
|   mRequestedPermissionsFromFragment = false
|   mResumed = false
|   mRetaining = false
|   mStopped = false
|   mStartedActivityFromFragment = false
|   mStartedIntentSenderFromFragment = false
|   mExtraDataMap = android.support.v4.util.SimpleArrayMap@317088256 (0x12e66200)
|   mActionBar = null
|   mActivityInfo = android.content.pm.ActivityInfo@317288192 (0x12e96f00)
|   mActivityTransitionState = android.app.ActivityTransitionState@316491264 (0x12dd4600)
|   mAllLoaderManagers = android.util.ArrayMap@317305344 (0x12e9b200)
|   mApplication = com.daxh.explore.myapp.MyAppApp@315135744 (0x12c89700)
|   mCalled = true
|   mChangeCanvasToTranslucent = false
|   mChangingConfigurations = false
|   mCheckedForLoaderManager = true
|   mComponent = android.content.ComponentName@316883056 (0x12e34070)
|   mConfigChangeFlags = 0
|   mContainer = android.app.Activity$1@316866912 (0x12e30160)
|   mCurrentConfig = android.content.res.Configuration@316862816 (0x12e2f160)
|   mDecor = com.android.internal.policy.impl.PhoneWindow$DecorView@316164096 (0x12d84800)
|   mDefaultKeyMode = 0
|   mDefaultKeySsb = null
|   mDestroyed = false
|   mDoReportFullyDrawn = true
|   mEmbeddedID = null
|   mEnableDefaultActionBarUp = false
|   mEnterTransitionListener = android.app.SharedElementCallback$1@1887233040 (0x707ce410)
|   mExitTransitionListener = android.app.SharedElementCallback$1@1887233040 (0x707ce410)
|   mFinished = false
|   mFragments = android.app.FragmentManagerImpl@314915296 (0x12c539e0)
|   mHandler = android.os.Handler@317088224 (0x12e661e0)
|   mIdent = 958616894
|   mInstanceTracker = android.os.StrictMode$InstanceTracker@316866928 (0x12e30170)
|   mInstrumentation = android.app.Instrumentation@314896144 (0x12c4ef10)
|   mIntent = android.content.Intent@316506176 (0x12dd8040)
|   mLastNonConfigurationInstances = null
|   mLoaderManager = null
|   mLoadersStarted = true
|   mMainThread = android.app.ActivityThread@314790144 (0x12c35100)
|   mManagedCursors = java.util.ArrayList@317088096 (0x12e66160)
|   mManagedDialogs = null
|   mMenuInflater = null
|   mParent = null
|   mReferrer = java.lang.String@317076800 (0x12e63540)
|   mResultCode = 0
|   mResultData = null
|   mResumed = true
|   mSearchManager = null
|   mStartedActivity = false
|   mStopped = false
|   mTemporaryPause = false
|   mTitle = java.lang.String@316515168 (0x12dda360)
|   mTitleColor = 0
|   mTitleReady = true
|   mToken = android.os.BinderProxy@317075616 (0x12e630a0)
|   mTranslucentCallback = null
|   mUiThread = java.lang.Thread@1948209064 (0x741f4fa8)
|   mVisibleBehind = false
|   mVisibleFromClient = true
|   mVisibleFromServer = true
|   mVoiceInteractor = null
|   mWindow = com.android.internal.policy.impl.PhoneWindow@315859200 (0x12d3a100)
|   mWindowAdded = true
|   mWindowManager = android.view.WindowManagerImpl@317089024 (0x12e66500)
|   mInflater = com.android.internal.policy.impl.PhoneLayoutInflater@317399872 (0x12eb2340)
|   mOverrideConfiguration = null
|   mResources = android.content.res.Resources@314730720 (0x12c268e0)
|   mTheme = android.content.res.Resources$Theme@317089088 (0x12e66540)
|   mThemeResource = 2131230884
|   mBase = android.app.ContextImpl@314923264 (0x12c55900)
* Instance of java.lang.String
|   static REPLACEMENT_CHAR = �
|   static serialVersionUID = -6849794470754667710
|   static ASCII = char[128]@1887135184 (0x707b65d0)
|   static $staticOverhead = byte[32]@1887282065 (0x707da391)
|   static CASE_INSENSITIVE_ORDER = java.lang.String$CaseInsensitiveComparator@1887134984 (0x707b6508)
|   count = 7
|   hashCode = 864575192
|   offset = 0
|   value = char[7]@316651840 (0x12dfb940)
* Excluded Refs:
| Field: android.view.inputmethod.InputMethodManager.mNextServedView
| Field: android.view.inputmethod.InputMethodManager.mServedView
| Field: android.view.inputmethod.InputMethodManager.mServedInputConnection
| Field: android.view.inputmethod.InputMethodManager.mCurRootView
| Field: android.animation.LayoutTransition$1.val$parent
| Field: android.view.textservice.SpellCheckerSession$1.this$0
| Field: android.support.v7.internal.widget.ActivityChooserModel.mActivityChoserModelPolicy
| Field: android.widget.ActivityChooserModel.mActivityChoserModelPolicy
| Field: android.accounts.AccountManager$AmsTask$Response.this$1
| Field: android.media.MediaScannerConnection.mContext
| Field: android.os.UserManager.mContext
| Field: android.media.AudioManager$1.this$0
| Field: android.widget.Editor$Blink.this$0
| Field: android.net.ConnectivityManager.sInstance
| Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
| Static field: android.text.TextLine.sCached
| Thread:FinalizerWatchdogDaemon (always)
| Thread:main (always)
| Thread:LeakCanary-Heap-Dump (always)
| Class:java.lang.ref.WeakReference (always)
| Class:java.lang.ref.SoftReference (always)
| Class:java.lang.ref.PhantomReference (always)
| Class:java.lang.ref.Finalizer (always)
| Class:java.lang.ref.FinalizerReference (always)

Любые идеи или объяснения, почему это происходит?


person daxh    schedule 08.01.2017    source источник


Ответы (1)


Похоже, проблема связана с моим неполным пониманием того, как использовать LeakCanary. Причина этой проблемы (и решение) объясняется здесь

https://stackoverflow.com/a/32881096/6583492

person daxh    schedule 08.01.2017