I'm testing my app with the new leak canary and on different devices (as well as virtual devices).
everything looks fine on all devices except one device which is the only one running Android 8.
the analyzing process looks fine but whenever it finishes it shows a few leaks (which other devices won't show!).
every time I check the trace I end up either with ReportFragment or InputMethodManager.
is anything actually leaking? is this an excluded leak?
thanks in advance

Can you share the full text leaktrace (click ... in the top right)?
sure thing:
here is a heap dump file too. but it's not for this particular leak, for a similar one.just in case.
I'm seeing a similar thing too from ReportFragment. Although in our case I am more inclined to believe we are doing something stupid with our app :smiley:. Here's our leak trace for comparison My.Leak.Trace.txt.
I'm happy to raise this in a different issue if it's better that way.
For me, the AccessibilityManager is holding onto it: leak.txt
Similar issue on Oreo(S8+) and Android Pie(Pixel2XL).
I have an app with TabLayout navigating via ViewPager having Fragments. Simply opening the app and swiping to the 3 Tabs and then closing causes a leak MainActivity and ReportFragment Leaks. I've googled but have no idea how to resolve them as yet.
reportfragment leak.txt
Uploading Mainactivityleak.txtβ¦
Note that your work Guys, is really highly appreciated. Thanks.
hi I got the leak on Pixel Emulator running Android 8.1 too, here is my leak trace
I've filed a bug with a repro case here for anyone that wants to follow: https://issuetracker.google.com/issues/112792715
Am I the only one or did they hide the issue from the public? oO
Yes. A comment was left before doing so to notify watchers. It is also
already fixed.
On Wed, Aug 22, 2018 at 3:59 PM Paul Woitaschek notifications@github.com
wrote:
Am I the only one or did they hide the issue from the public? oO
β
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/square/leakcanary/issues/1081#issuecomment-415160114,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEETmcmCzof13yl_P8WI01Ysb80W_nks5uTbgmgaJpZM4Vvzbx
.
Thanks, found the mail. If someone is wondering:
[email protected] added comment #9:
This is in the framework, not in the support library. Thanks for reporting it. I'm going to move it to the correct internal component, which will cut off public access to it (sorry).
So this is an Android issue starting with Oreo? It also occurs on a Pixel with Android Pie. Will this be fixed in a monthly security update or do we have to wait for Android 9.1 or even 10?
You'll have to wait till it's fixed in AOSP. It's such a nuisance that I've actually just disabled leakcanary on P all together :/
For late readers, this is the proper leaktrace:
In com.ddsafricaltd.fieldmetrics:6.0:2018081101.
* android.arch.lifecycle.ReportFragment has leaked:
* static ViewGroup$ViewLocationHolder.!(sPool)!
* β³ Pools$SynchronizedPool.!(mPool)!
* β³ array Object[].!([3])!
* β³ ViewGroup$ViewLocationHolder.!(mRoot)!
* β³ LinearLayout.mContext
* β³ MainActivity.mFragments
* β³ FragmentController.mHost
* β³ Activity$HostCallbacks.mFragmentManager
* β³ FragmentManagerImpl.mAdded
* β³ ArrayList.elementData
* β³ array Object[].[0]
* β³ ReportFragment
* Reference Key: b114064f-db10-4fab-8166-e08179003461
* Device: Google google Pixel 2 XL taimen
* Android Version: 9 API: 28 LeakCanary: 1.6.1 26145bf
* Durations: watch=75812ms, gc=235ms, heap dump=3866ms, analysis=7645ms
* Details:
* Class android.view.ViewGroup$ViewLocationHolder
| static $class$dexTypeIndex = 4622
| static $class$ifTable = java.lang.Object[2]@321728464 (0x132d2fd0)
| static $class$dexCache = java.lang.DexCache@1893249352 (0x70d8b148)
| static $class$accessFlags = 524288
| static $class$name = null
| static $class$componentType = null
| static $class$iFields = 535328457232
| static $class$clinitThreadId = 4551
| static $class$numReferenceStaticFields = 1
| static $class$superClass = java.lang.Object
| static $classOverhead = byte[124]@319405305 (0x1309bcf9)
| static $class$objectSizeAllocFastPath = 24
| static $class$dexClassDefIndex = 2017
| static $class$primitiveType = 131072
| static $class$classSize = 268
| static $class$vtable = null
| static MAX_POOL_SIZE = 32
| static $class$referenceInstanceOffsets = 7
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 535328457304
| static COMPARISON_STRATEGY_LOCATION = 2
| static $class$extData = null
| static $class$objectSize = 24
| static $class$classLoader = null
| static $class$virtualMethodsOffset = 9
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = 0
| static $class$numReferenceInstanceFields = 3
| static $class$sFields = 535328457144
| static COMPARISON_STRATEGY_STRIPE = 1
| static sComparisonStrategy = 1
| static sPool = android.util.Pools$SynchronizedPool@321728488 (0x132d2fe8)
| static $class$status = -536870912
| static $class$copiedMethodsOffset = 12
* Instance of android.util.Pools$SynchronizedPool
| static $class$dexTypeIndex = 4136
| static $class$ifTable = java.lang.Object[2]@1893372152 (0x70da90f8)
| static $class$dexCache = java.lang.DexCache@1893249352 (0x70d8b148)
| static $class$accessFlags = 524289
| static $class$name = "android.util.Pools$SynchronizedPool"
| static $class$componentType = null
| static $class$iFields = 1899522280
| static $class$clinitThreadId = 0
| static $class$numReferenceStaticFields = 0
| static $class$superClass = android.util.Pools$SimplePool
| static $classOverhead = byte[116]@1896706545 (0x710d71f1)
| static $class$objectSizeAllocFastPath = 24
| static $class$dexClassDefIndex = 5340
| static $class$primitiveType = 131072
| static $class$classSize = 240
| static $class$vtable = null
| static $class$referenceInstanceOffsets = 5
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 1902393744
| static $class$extData = null
| static $class$objectSize = 20
| static $class$classLoader = null
| static $class$virtualMethodsOffset = 2
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = 536870912
| static $class$numReferenceInstanceFields = 1
| static $class$sFields = 0
| static $class$status = -536870912
| static $class$copiedMethodsOffset = 4
| mLock = java.lang.Object@321728656 (0x132d3090)
| mPool = java.lang.Object[32]@321728512 (0x132d3000)
| mPoolSize = 4
| shadow$_klass_ = android.util.Pools$SynchronizedPool
| shadow$_monitor_ = 0
* Array of java.lang.Object[]
| [0] = android.view.ViewGroup$ViewLocationHolder@321728664 (0x132d3098)
| [1] = android.view.ViewGroup$ViewLocationHolder@321728688 (0x132d30b0)
| [2] = android.view.ViewGroup$ViewLocationHolder@321728712 (0x132d30c8)
| [3] = android.view.ViewGroup$ViewLocationHolder@321728736 (0x132d30e0)
| [4] = null
| [5] = null
| [6] = null
| [7] = null
| [8] = null
| [9] = null
| [10] = null
| [11] = null
| [12] = null
| [13] = null
| [14] = null
| [15] = null
| [16] = null
| [17] = null
| [18] = null
| [19] = null
| [20] = null
| [21] = null
| [22] = null
| [23] = null
| [24] = null
| [25] = null
| [26] = null
| [27] = null
| [28] = null
| [29] = null
| [30] = null
| [31] = null
* Instance of android.view.ViewGroup$ViewLocationHolder
| static $class$dexTypeIndex = 4622
| static $class$ifTable = java.lang.Object[2]@321728464 (0x132d2fd0)
| static $class$dexCache = java.lang.DexCache@1893249352 (0x70d8b148)
| static $class$accessFlags = 524288
| static $class$name = null
| static $class$componentType = null
| static $class$iFields = 535328457232
| static $class$clinitThreadId = 4551
| static $class$numReferenceStaticFields = 1
| static $class$superClass = java.lang.Object
| static $classOverhead = byte[124]@319405305 (0x1309bcf9)
| static $class$objectSizeAllocFastPath = 24
| static $class$dexClassDefIndex = 2017
| static $class$primitiveType = 131072
| static $class$classSize = 268
| static $class$vtable = null
| static MAX_POOL_SIZE = 32
| static $class$referenceInstanceOffsets = 7
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 535328457304
| static COMPARISON_STRATEGY_LOCATION = 2
| static $class$extData = null
| static $class$objectSize = 24
| static $class$classLoader = null
| static $class$virtualMethodsOffset = 9
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = 0
| static $class$numReferenceInstanceFields = 3
| static $class$sFields = 535328457144
| static COMPARISON_STRATEGY_STRIPE = 1
| static sComparisonStrategy = 1
| static sPool = android.util.Pools$SynchronizedPool@321728488 (0x132d2fe8)
| static $class$status = -536870912
| static $class$copiedMethodsOffset = 12
| mLayoutDirection = 0
| mLocation = android.graphics.Rect@321728760 (0x132d30f8)
| mRoot = android.widget.LinearLayout@321728784 (0x132d3110)
| mView = null
| shadow$_klass_ = android.view.ViewGroup$ViewLocationHolder
| shadow$_monitor_ = 0
* Instance of android.widget.LinearLayout
| static $class$dexTypeIndex = 5524
| static $class$ifTable = java.lang.Object[10]@1893739392 (0x70e02b80)
| static VERTICAL_GRAVITY_COUNT = 4
| static $class$dexCache = java.lang.DexCache@1893249352 (0x70d8b148)
| static HORIZONTAL = 0
| static $class$accessFlags = 524289
| static $class$name = "android.widget.LinearLayout"
| static SHOW_DIVIDER_BEGINNING = 1
| static sCompatibilityDone = true
| static $class$componentType = null
| static $class$iFields = 1899166828
| static INDEX_FILL = 3
| static $class$clinitThreadId = 0
| static $class$numReferenceStaticFields = 0
| static INDEX_BOTTOM = 2
| static VERTICAL = 1
| static $class$superClass = android.view.ViewGroup
| static $classOverhead = byte[8004]@1894502489 (0x70ebd059)
| static $class$objectSizeAllocFastPath = 680
| static INDEX_TOP = 1
| static $class$dexClassDefIndex = 6000
| static $class$primitiveType = 131072
| static $class$classSize = 8174
| static $class$vtable = null
| static $class$referenceInstanceOffsets = -1073741824
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 1901153336
| static $class$extData = null
| static INDEX_CENTER_VERTICAL = 0
| static $class$objectSize = 676
| static $class$classLoader = null
| static $class$virtualMethodsOffset = 11
| static sRemeasureWeightedChildren = false
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = 536870912
| static $class$numReferenceInstanceFields = 3
| static $class$sFields = 1899166616
| static SHOW_DIVIDER_END = 4
| static SHOW_DIVIDER_NONE = 0
| static $class$status = -536870912
| static SHOW_DIVIDER_MIDDLE = 2
| static $class$copiedMethodsOffset = 63
| mAllowInconsistentMeasurement = false
| mBaselineAligned = true
| mBaselineAlignedChildIndex = -1
| mBaselineChildTop = 0
| mDivider = null
| mDividerHeight = 0
| mDividerPadding = 0
| mDividerWidth = 0
| mGravity = 8388659
| mLayoutDirection = 0
| mMaxAscent = null
| mMaxDescent = null
| mOrientation = 1
| mShowDividers = 0
| mTotalLength = 172
| mUseLargestChild = false
| mWeightSum = -1.0
| mAnimationListener = null
| mCachePaint = null
| mChildCountWithTransientState = 0
| mChildTransformation = null
| mChildUnhandledKeyListeners = 0
| mChildren = android.view.View[12]@321729464 (0x132d33b8)
| mChildrenCount = 1
| mChildrenInterestedInDrag = null
| mCurrentDragChild = null
| mCurrentDragStartEvent = null
| mDefaultFocus = null
| mDisappearingChildren = null
| mFirstHoverTarget = null
| mFirstTouchTarget = null
| mFocused = null
| mFocusedInCluster = null
| mGroupFlags = 2244691
| mHoveredSelf = false
| mInvalidateRegion = null
| mInvalidationTransformation = null
| mIsInterestedInDrag = false
| mLastTouchDownIndex = -1
| mLastTouchDownTime = 0
| mLastTouchDownX = 0.0
| mLastTouchDownY = 0.0
| mLayoutAnimationController = null
| mLayoutCalledWhileSuppressed = false
| mLayoutMode = -1
| mLayoutTransitionListener = android.view.ViewGroup$4@321729528 (0x132d33f8)
| mLocalPoint = null
| mNestedScrollAxes = 0
| mOnHierarchyChangeListener = null
| mPersistentDrawingCache = 2
| mPreSortedChildren = null
| mSuppressLayout = false
| mTempPoint = null
| mTooltipHoverTarget = null
| mTooltipHoveredSelf = false
| mTransientIndices = null
| mTransientViews = null
| mTransition = null
| mTransitioningViews = null
| mVisibilityChangingChildren = null
| mAccessibilityCursorPosition = -1
| mAccessibilityDelegate = null
| mAccessibilityPaneTitle = null
| mAccessibilityTraversalAfterId = -1
| mAccessibilityTraversalBeforeId = -1
| mAccessibilityViewId = 212
| mAnimator = null
| mAttachInfo = null
| mAttributes = null
| mAutofillHints = null
| mAutofillId = null
| mAutofillViewId = -1
| mBackground = android.graphics.drawable.GradientDrawable@321729544 (0x132d3408)
| mBackgroundRenderNode = android.view.RenderNode@321729632 (0x132d3460)
| mBackgroundResource = 0
| mBackgroundSizeChanged = false
| mBackgroundTint = null
| mBottom = 172
| mCachingFailed = false
| mClipBounds = null
| mContentDescription = null
| mContext = com.ddsafricaltd.fieldmetrics.activities.MainActivity@321729656 (0x132d3478)
| mCurrentAnimation = null
| mDefaultFocusHighlight = null
| mDefaultFocusHighlightCache = null
| mDefaultFocusHighlightEnabled = true
| mDefaultFocusHighlightSizeChanged = true
| mDrawableState = int[2]@1894217152 (0x70e775c0)
| mDrawingCache = null
| mDrawingCacheBackgroundColor = 0
| mFloatingTreeObserver = null
| mForegroundInfo = null
| mFrameMetricsObservers = null
| mGhostView = null
| mHasPerformedLongPress = false
| mID = -1
| mIgnoreNextUpEvent = false
| mInContextButtonPress = false
| mInputEventConsistencyVerifier = null
| mKeyedTags = null
| mLabelForId = -1
| mLastIsOpaque = false
| mLayerPaint = null
| mLayerType = 0
| mLayoutInsets = null
| mLayoutParams = android.view.WindowManager$LayoutParams@321730272 (0x132d36e0)
| mLeft = 0
| mLeftPaddingDefined = false
| mListenerInfo = null
| mLongClickX = NaN
| mLongClickY = NaN
| mMatchIdPredicate = null
| mMatchLabelForPredicate = null
| mMeasureCache = android.util.LongSparseLongArray@321730456 (0x132d3798)
| mMeasuredHeight = 172
| mMeasuredWidth = 854
| mMinHeight = 0
| mMinWidth = 0
| mNestedScrollingParent = null
| mNextClusterForwardId = -1
| mNextFocusDownId = -1
| mNextFocusForwardId = -1
| mNextFocusLeftId = -1
| mNextFocusRightId = -1
| mNextFocusUpId = -1
| mOldHeightMeasureSpec = -2147481037
| mOldWidthMeasureSpec = -2147482528
| mOutlineProvider = android.view.ViewOutlineProvider$1@1893475968 (0x70dc2680)
| mOverScrollMode = 1
| mOverlay = null
| mPaddingBottom = 0
| mPaddingLeft = 0
| mPaddingRight = 0
| mPaddingTop = 0
| mParent = null
| mPendingCheckForLongPress = null
| mPendingCheckForTap = null
| mPerformClick = null
| mPointerIcon = null
| mPrivateFlags = -2128607184
| mPrivateFlags2 = 1611867680
| mPrivateFlags3 = 0
| mRecreateDisplayList = false
| mRenderNode = android.view.RenderNode@321730480 (0x132d37b0)
| mResources = android.content.res.Resources@321730504 (0x132d37c8)
| mRight = 854
| mRightPaddingDefined = false
| mRoundScrollbarRenderer = null
| mRunQueue = null
| mScrollCache = null
| mScrollIndicatorDrawable = null
| mScrollX = 0
| mScrollY = 0
| mSendViewScrolledAccessibilityEvent = null
| mSendingHoverAccessibilityEvents = false
| mStartActivityRequestWho = null
| mStateListAnimator = null
| mSystemUiVisibility = 0
| mTag = null
| mTempNestedScrollConsumed = null
| mTooltipInfo = null
| mTop = 0
| mTouchDelegate = null
| mTouchSlop = 28
| mTransformationInfo = null
| mTransientStateCount = 0
| mTransitionName = null
| mUnscaledDrawingCache = null
| mUnsetPressedState = null
| mUserPaddingBottom = 0
| mUserPaddingEnd = -2147483648
| mUserPaddingLeft = 0
| mUserPaddingLeftInitial = 0
| mUserPaddingRight = 0
| mUserPaddingRightInitial = 0
| mUserPaddingStart = -2147483648
| mVerticalScrollFactor = 0.0
| mVerticalScrollbarPosition = 0
| mViewFlags = 402653328
| mVisibilityChangeForAutofillHandler = null
| mWindowAttachCount = 1
| shadow$_klass_ = android.widget.LinearLayout
| shadow$_monitor_ = -2075687360
* Instance of com.ddsafricaltd.fieldmetrics.activities.MainActivity
| static $class$dexTypeIndex = 526
| static $class$ifTable = java.lang.Object[62]@320352488 (0x131830e8)
| static $class$dexCache = java.lang.DexCache@320064464 (0x1313cbd0)
| static hasBeenCreated = false
| static $class$accessFlags = 524289
| static $class$name = "com.ddsafricaltd.fieldmetrics.activities.MainActivity"
| static $class$componentType = null
| static $class$iFields = 532712420584
| static $class$clinitThreadId = 4551
| static $class$numReferenceStaticFields = 1
| static $class$superClass = android.support.v7.app.AppCompatActivity
| static $classOverhead = byte[4788]@320152585 (0x13152409)
| static $class$objectSizeAllocFastPath = 616
| static NUMLOOKUPS = 10
| static $class$dexClassDefIndex = 1026
| static REQUEST_CHECK_SETTINGS = 1
| static $class$primitiveType = 131072
| static $class$classSize = 4929
| static $class$vtable = null
| static PLAY_SERVICES_RESOLUTION_REQUEST = 1000
| static $class$referenceInstanceOffsets = -1073741824
| static Spinner_OnKey = com.ddsafricaltd.fieldmetrics.activities.MainActivity$34@320352824 (0x13183238)
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 532712422016
| static $class$extData = null
| static $class$objectSize = 616
| static $class$classLoader = dalvik.system.PathClassLoader@319417192 (0x1309eb68)
| static $class$virtualMethodsOffset = 108
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = -1960235794
| static $class$numReferenceInstanceFields = 57
| static $class$sFields = 532712420496
| static $class$status = -536870912
| static $class$copiedMethodsOffset = 174
| CURRENT_FRAGMENT = 0
| CurrentPJP_User_Outlet = null
| FRAGMENT_ACTIVITY_LOG = 40
| FRAGMENT_ACTIVITY_OUTLET_MAP = 50
| FRAGMENT_OUTLETS = 20
| FRAGMENT_OUTLET_INFO = 21
| FRAGMENT_PROFILE = 30
| FRAGMENT_SETTINGS = 10
| GPSLocationManagerService = null
| GPS_Listener_Initialized = true
| INT_PJPMODE = 1
| SpinnerToolbar = android.support.v7.widget.AppCompatSpinner@321731488 (0x132d3ba0)
| Spinner_OnTouch = com.ddsafricaltd.fieldmetrics.activities.MainActivity$33@321732328 (0x132d3ee8)
| alertDialogBuilder = null
| alertGPS = null
| alertNetwork = null
| appbar = null
| arrQuestionAnswerStats = null
| blnByPassOutletConfirmation = false
| blnGPSAlertIsVisible = false
| blnInstanceOfCuttOffAlreadyRunning = false
| blnLastSavedOutletListSetting = false
| blnMissingQuestionsCheckMode = false
| blnNetworkAlertIsVisible = false
| blnRealTimeGPSMode = false
| blnShowSearchVsSpinner = true
| btnShowLocation = null
| btnStartLocationUpdates = null
| bundle = null
| db = com.ddsafricaltd.fieldmetrics.globalSupportRoutines.DatabaseRoutines@320312952 (0x13179678)
| df = java.text.DecimalFormat@321732344 (0x132d3ef8)
| distToHome = 0.0
| fragmentManager = android.support.v4.app.FragmentManagerImpl@321732408 (0x132d3f38)
| fragmentMapOutlet = null
| fragmentMessages = com.ddsafricaltd.fieldmetrics.fragments.fragment_gcm_messages@321732520 (0x132d3fa8)
| fragmentQuestions = com.ddsafricaltd.fieldmetrics.fragments.fragment_questions@321732720 (0x132d4070)
| fragment_adapter = com.ddsafricaltd.fieldmetrics.activities.MainActivity$Adapter@321733040 (0x132d41b0)
| gps = null
| gpsStateReceiver = com.ddsafricaltd.fieldmetrics.globalSupportRoutines.GPSStateReceiver@321733088 (0x132d41e0)
| holderOutlets = com.ddsafricaltd.fieldmetrics.pojos.HolderOutlets@321733104 (0x132d41f0)
| imgMainActivityLogo = android.support.v7.widget.AppCompatImageView@321733240 (0x132d4278)
| intAllowOutletCreation = 1
| intDataStarted = 100
| intEnforceGPSMapping = 1
| intGPSResultCode = 10
| intOutletIDToCheckQuestionsFor = 0
| intTimesToastIsShown = 0
| kalmanLatLong = null
| lastPress = 1534252129233
| lblLocation = null
| lngNanoStartTime = 0
| lngstartTime = 0
| lngstarttime = 0
| locCounter = 10
| mFirebaseAnalytics = com.google.firebase.analytics.FirebaseAnalytics@320408624 (0x13190c30)
| mGoogleApiClient = null
| mGoogleError = false
| mInAppBroadcastReceiver = com.ddsafricaltd.fieldmetrics.activities.MainActivity$5@321733808 (0x132d44b0)
| mIntentFilter = android.content.IntentFilter@321733832 (0x132d44c8)
| mLastUpdateTime = null
| mLocalBroadcastManager = android.support.v4.content.LocalBroadcastManager@320812944 (0x131f3790)
| mLocationRequest = null
| mRequestingLocationUpdates = false
| mTracker = com.google.android.gms.analytics.Tracker@321088360 (0x13236b68)
| networkChangeReceiver = com.ddsafricaltd.fieldmetrics.globalSupportRoutines.NetworkChangeReceiver@321733888 (0x132d4500)
| notifClickReceiver = null
| objCheckIfDBIsCorruptAsync = com.ddsafricaltd.fieldmetrics.activities.MainActivity$CheckIfDBIsCorruptAsync@321733904 (0x132d4510)
| objFetchSettings = null
| objInsertUserQuestionsToTrans = null
| objManualAnswerUpload = null
| objQuestionAnswerStatus = null
| objQuestionAnswerStatus2 = null
| objQuestionCountForOutlet = null
| objRunGenericSqlCommand = null
| objSaveMessageToDB = null
| objSaveSettings = null
| progressBarMainActivity = android.widget.ProgressBar@321733944 (0x132d4538)
| singleton = null
| tabLayout = android.support.design.widget.TabLayout@321734512 (0x132d4770)
| timeChangedReceiver = null
| toolbar = android.support.v7.widget.Toolbar@321735344 (0x132d4ab0)
| txtBlueTop = android.support.v7.widget.AppCompatTextView@321736120 (0x132d4db8)
| txtCancelMain = android.support.v7.widget.AppCompatTextView@321736944 (0x132d50f0)
| txtGreenBottom = android.support.v7.widget.AppCompatTextView@321737768 (0x132d5428)
| txtIsDev = android.support.v7.widget.AppCompatTextView@321738592 (0x132d5760)
| txtMainActivityDisplay = android.support.v7.widget.AppCompatTextView@321739416 (0x132d5a98)
| txtRetailFieldMetricsUnderlogo = android.support.v7.widget.AppCompatTextView@321740240 (0x132d5dd0)
| viewPager = android.support.v4.view.ViewPager@321741064 (0x132d6108)
| wantLocations = true
| mDelegate = android.support.v7.app.AppCompatDelegateImplN@321741888 (0x132d6440)
| mResources = null
| mThemeId = 2131689645
| mCreated = true
| mFragments = android.support.v4.app.FragmentController@321742032 (0x132d64d0)
| mHandler = android.support.v4.app.FragmentActivity$1@321742048 (0x132d64e0)
| mLoaderManager = null
| mNextCandidateRequestIndex = 0
| mPendingFragmentActivityResults = android.support.v4.util.SparseArrayCompat@321742080 (0x132d6500)
| mReallyStopped = true
| mRequestedPermissionsFromFragment = false
| mResumed = false
| mRetaining = false
| mStopped = true
| mViewModelStore = null
| mStartedActivityFromFragment = false
| mStartedIntentSenderFromFragment = false
| mExtraDataMap = android.support.v4.util.SimpleArrayMap@321742104 (0x132d6518)
| mLifecycleRegistry = android.arch.lifecycle.LifecycleRegistry@321742128 (0x132d6530)
| mActionBar = null
| mActionModeTypeStarting = 0
| mActivityInfo = android.content.pm.ActivityInfo@321742160 (0x132d6550)
| mActivityTransitionState = android.app.ActivityTransitionState@321742312 (0x132d65e8)
| mApplication = com.ddsafricaltd.fieldmetrics.base.baseFieldMetrics@319430688 (0x130a2020)
| mAutoFillIgnoreFirstResumePause = false
| mAutoFillResetNeeded = false
| mAutofillManager = null
| mAutofillPopupWindow = null
| mCalled = true
| mCanEnterPictureInPicture = false
| mChangeCanvasToTranslucent = false
| mChangingConfigurations = false
| mComponent = android.content.ComponentName@321742368 (0x132d6620)
| mConfigChangeFlags = 0
| mCurrentConfig = android.content.res.Configuration@321742384 (0x132d6630)
| mDecor = null
| mDefaultKeyMode = 0
| mDefaultKeySsb = null
| mDestroyed = true
| mDoReportFullyDrawn = false
| mEmbeddedID = null
| mEnableDefaultActionBarUp = false
| mEnterTransitionListener = android.app.SharedElementCallback$1@1893386296 (0x70dac838)
| mExitTransitionListener = android.app.SharedElementCallback$1@1893386296 (0x70dac838)
| mFinished = true
| mFragments = android.app.FragmentController@321742496 (0x132d66a0)
| mHandler = android.os.Handler@321742512 (0x132d66b0)
| mHasCurrentPermissionsRequest = false
| mIdent = 190401265
| mInstanceTracker = android.os.StrictMode$InstanceTracker@321742544 (0x132d66d0)
| mInstrumentation = android.app.Instrumentation@320471240 (0x131a00c8)
| mIntent = android.content.Intent@321742560 (0x132d66e0)
| mLastAutofillId = 1073741825
| mLastNonConfigurationInstances = null
| mMainThread = android.app.ActivityThread@319291816 (0x130801a8)
| mManagedCursors = java.util.ArrayList@321742624 (0x132d6720)
| mManagedDialogs = null
| mMenuInflater = null
| mParent = null
| mReferrer = "com.ddsafricaltd.fieldmetrics"
| mRestoredFromBundle = false
| mResultCode = 0
| mResultData = null
| mResumed = false
| mSearchEvent = null
| mSearchManager = null
| mStartedActivity = false
| mStopped = true
| mTaskDescription = android.app.ActivityManager$TaskDescription@321742696 (0x132d6768)
| mTemporaryPause = false
| mTitle = "Field Metrics"
| mTitleColor = 0
| mTitleReady = true
| mToken = android.os.BinderProxy@321742768 (0x132d67b0)
| mTranslucentCallback = null
| mUiThread = java.lang.Thread@1967573624 (0x7546ca78)
| mVisibleFromClient = true
| mVisibleFromServer = false
| mVoiceInteractor = null
| mWindow = com.android.internal.policy.PhoneWindow@321742792 (0x132d67c8)
| mWindowAdded = true
| mWindowManager = android.view.WindowManagerImpl@321743168 (0x132d6940)
| mInflater = com.android.internal.policy.PhoneLayoutInflater@321743192 (0x132d6958)
| mOverrideConfiguration = null
| mResources = android.content.res.Resources@321730504 (0x132d37c8)
| mTheme = android.content.res.Resources$Theme@321743240 (0x132d6988)
| mThemeResource = 2131689645
| mBase = android.app.ContextImpl@321743256 (0x132d6998)
| shadow$_klass_ = com.ddsafricaltd.fieldmetrics.activities.MainActivity
| shadow$_monitor_ = -1882115313
* Instance of android.app.FragmentController
| static $class$dexTypeIndex = 547
| static $class$ifTable = java.lang.Object[0]@1891798952 (0x70c28fa8)
| static $class$dexCache = java.lang.DexCache@1893249256 (0x70d8b0e8)
| static $class$accessFlags = 524289
| static $class$name = "android.app.FragmentController"
| static $class$componentType = null
| static $class$iFields = 1899316064
| static $class$clinitThreadId = 0
| static $class$numReferenceStaticFields = 0
| static $class$superClass = java.lang.Object
| static $classOverhead = byte[412]@1896134193 (0x7104b631)
| static $class$objectSizeAllocFastPath = 16
| static $class$dexClassDefIndex = 303
| static $class$primitiveType = 131072
| static $class$classSize = 536
| static $class$vtable = null
| static $class$referenceInstanceOffsets = 1
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 1901690088
| static $class$extData = null
| static $class$objectSize = 12
| static $class$classLoader = null
| static $class$virtualMethodsOffset = 2
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = 536870912
| static $class$numReferenceInstanceFields = 1
| static $class$sFields = 0
| static $class$status = -536870912
| static $class$copiedMethodsOffset = 41
| mHost = android.app.Activity$HostCallbacks@321776432 (0x132deb30)
| shadow$_klass_ = android.app.FragmentController
| shadow$_monitor_ = 0
* Instance of android.app.Activity$HostCallbacks
| static $class$dexTypeIndex = 355
| static $class$ifTable = java.lang.Object[0]@1891798952 (0x70c28fa8)
| static $class$dexCache = java.lang.DexCache@1893249256 (0x70d8b0e8)
| static $class$accessFlags = 524288
| static $class$name = "android.app.Activity$HostCallbacks"
| static $class$componentType = null
| static $class$iFields = 1898886064
| static $class$clinitThreadId = 0
| static $class$numReferenceStaticFields = 0
| static $class$superClass = android.app.FragmentHostCallback
| static $classOverhead = byte[364]@1895176241 (0x70f61831)
| static $class$objectSizeAllocFastPath = 48
| static $class$dexClassDefIndex = 5011
| static $class$primitiveType = 131072
| static $class$classSize = 488
| static $class$vtable = null
| static $class$referenceInstanceOffsets = 319
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 1900272992
| static $class$extData = null
| static $class$objectSize = 44
| static $class$classLoader = null
| static $class$virtualMethodsOffset = 1
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = 536870912
| static $class$numReferenceInstanceFields = 1
| static $class$sFields = 0
| static $class$status = -536870912
| static $class$copiedMethodsOffset = 17
| this$0 = com.ddsafricaltd.fieldmetrics.activities.MainActivity@321729656 (0x132d3478)
| mActivity = com.ddsafricaltd.fieldmetrics.activities.MainActivity@321729656 (0x132d3478)
| mAllLoaderManagers = android.util.ArrayMap@321776480 (0x132deb60)
| mCheckedForLoaderManager = true
| mContext = com.ddsafricaltd.fieldmetrics.activities.MainActivity@321729656 (0x132d3478)
| mFragmentManager = android.app.FragmentManagerImpl@321776512 (0x132deb80)
| mHandler = android.os.Handler@321742512 (0x132d66b0)
| mLoaderManager = null
| mLoadersStarted = true
| mRetainLoaders = false
| mWindowAnimations = 0
| shadow$_klass_ = android.app.Activity$HostCallbacks
| shadow$_monitor_ = 0
* Instance of android.app.FragmentManagerImpl
| static $class$dexTypeIndex = 560
| static $class$ifTable = java.lang.Object[4]@1893804904 (0x70e12b68)
| static $class$dexCache = java.lang.DexCache@1893249256 (0x70d8b0e8)
| static $class$accessFlags = 524304
| static $class$name = "android.app.FragmentManagerImpl"
| static $class$componentType = null
| static VIEW_STATE_TAG = "android:view_state"
| static $class$iFields = 1899063816
| static $class$clinitThreadId = 0
| static TARGET_STATE_TAG = "android:target_state"
| static $class$numReferenceStaticFields = 5
| static TAG = "FragmentManager"
| static TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state"
| static $class$superClass = android.app.FragmentManager
| static $classOverhead = byte[916]@1894490841 (0x70eba2d9)
| static $class$objectSizeAllocFastPath = 112
| static $class$dexClassDefIndex = 5028
| static $class$primitiveType = 131072
| static USER_VISIBLE_HINT_TAG = "android:user_visible_hint"
| static $class$classSize = 1061
| static $class$vtable = null
| static DEBUG = false
| static $class$referenceInstanceOffsets = 4194303
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 1900949840
| static $class$extData = null
| static $class$objectSize = 110
| static $class$classLoader = null
| static $class$virtualMethodsOffset = 30
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = 536870912
| static $class$numReferenceInstanceFields = 22
| static $class$sFields = 1899063716
| static $class$status = -536870912
| static $class$copiedMethodsOffset = 132
| mActive = android.util.SparseArray@321776624 (0x132debf0)
| mAdded = java.util.ArrayList@321776648 (0x132dec08)
| mAllowOldReentrantBehavior = false
| mAvailBackStackIndices = null
| mBackStack = null
| mBackStackChangeListeners = null
| mBackStackIndices = null
| mContainer = null
| mCreatedMenus = null
| mCurState = 0
| mDestroyed = true
| mExecCommit = android.app.FragmentManagerImpl$1@321776672 (0x132dec20)
| mExecutingActions = false
| mHavePendingDeferredStart = false
| mHost = null
| mLifecycleCallbacks = java.util.concurrent.CopyOnWriteArrayList@321776688 (0x132dec30)
| mNeedMenuInvalidate = false
| mNextFragmentIndex = 1
| mNoTransactionsBecause = null
| mParent = null
| mPendingActions = java.util.ArrayList@321776704 (0x132dec40)
| mPostponedTransactions = null
| mPrimaryNav = null
| mSavedNonConfig = null
| mStateArray = null
| mStateBundle = null
| mStateSaved = false
| mTmpAddedFragments = java.util.ArrayList@321776728 (0x132dec58)
| mTmpIsPop = java.util.ArrayList@321776752 (0x132dec70)
| mTmpRecords = java.util.ArrayList@321776776 (0x132dec88)
| shadow$_klass_ = android.app.FragmentManagerImpl
| shadow$_monitor_ = 0
* Instance of java.util.ArrayList
| static $class$dexTypeIndex = 1417
| static $class$ifTable = java.lang.Object[12]@1887487328 (0x7080c560)
| static $class$dexCache = java.lang.DexCache@1887109360 (0x707b00f0)
| static $class$accessFlags = 524289
| static $class$name = "java.util.ArrayList"
| static $class$componentType = null
| static EMPTY_ELEMENTDATA = java.lang.Object[0]@1890322656 (0x70ac08e0)
| static $class$iFields = 1888539960
| static DEFAULT_CAPACITY = 10
| static MAX_ARRAY_SIZE = 2147483639
| static $class$clinitThreadId = 0
| static serialVersionUID = 8683452581122892189
| static $class$numReferenceStaticFields = 2
| static DEFAULTCAPACITY_EMPTY_ELEMENTDATA = java.lang.Object[0]@1893471960 (0x70dc16d8)
| static $class$superClass = java.util.AbstractList
| static $classOverhead = byte[364]@1887527113 (0x708160c9)
| static $class$objectSizeAllocFastPath = 24
| static $class$dexClassDefIndex = 3077
| static $class$primitiveType = 131072
| static $class$classSize = 512
| static $class$vtable = null
| static $class$referenceInstanceOffsets = 2
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 1888681872
| static $class$extData = null
| static $class$objectSize = 20
| static $class$classLoader = null
| static $class$virtualMethodsOffset = 15
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = -1363712915
| static $class$numReferenceInstanceFields = 1
| static $class$sFields = 1888539876
| static $class$status = -536870912
| static $class$copiedMethodsOffset = 46
| elementData = java.lang.Object[10]@321777064 (0x132deda8)
| size = 1
| modCount = 1
| shadow$_klass_ = java.util.ArrayList
| shadow$_monitor_ = 0
* Array of java.lang.Object[]
| [0] = android.arch.lifecycle.ReportFragment@321777120 (0x132dede0)
| [1] = null
| [2] = null
| [3] = null
| [4] = null
| [5] = null
| [6] = null
| [7] = null
| [8] = null
| [9] = null
* Instance of android.arch.lifecycle.ReportFragment
| static $class$dexTypeIndex = 135
| static $class$ifTable = java.lang.Object[6]@320797536 (0x131efb60)
| static $class$dexCache = java.lang.DexCache@319666776 (0x130dba58)
| static $class$accessFlags = 524289
| static $class$name = "android.arch.lifecycle.ReportFragment"
| static $class$componentType = null
| static $class$iFields = 532712444408
| static $class$clinitThreadId = 4551
| static $class$numReferenceStaticFields = 1
| static $class$superClass = android.app.Fragment
| static $classOverhead = byte[1316]@319776057 (0x130f6539)
| static $class$objectSizeAllocFastPath = 128
| static REPORT_FRAGMENT_TAG = "android.arch.lifecycle.LifecycleDispatcher.report_fragment_tag"
| static $class$dexClassDefIndex = 30
| static $class$primitiveType = 131072
| static $class$classSize = 1444
| static $class$vtable = null
| static $class$referenceInstanceOffsets = 268500991
| static $class$shadow$_klass_ = java.lang.Class
| static $class$methods = 532712444432
| static $class$extData = null
| static $class$objectSize = 124
| static $class$classLoader = dalvik.system.PathClassLoader@319417192 (0x1309eb68)
| static $class$virtualMethodsOffset = 7
| static $class$classFlags = 0
| static $class$shadow$_monitor_ = 0
| static $class$numReferenceInstanceFields = 1
| static $class$sFields = 532712444384
| static $class$status = -536870912
| static $class$copiedMethodsOffset = 14
| mProcessListener = null
| mAdded = false
| mAnimationInfo = null
| mArguments = null
| mBackStackNesting = 0
| mCalled = true
| mCheckedForLoaderManager = false
| mChildFragmentManager = null
| mChildNonConfig = null
| mContainer = null
| mContainerId = 0
| mDeferStart = false
| mDetached = false
| mFragmentId = 0
| mFragmentManager = null
| mFromLayout = false
| mHasMenu = false
| mHidden = false
| mHiddenChanged = false
| mHost = null
| mInLayout = false
| mIndex = -1
| mIsCreated = false
| mIsNewlyAdded = false
| mLayoutInflater = null
| mLoaderManager = null
| mLoadersStarted = false
| mMenuVisible = true
| mParentFragment = null
| mPerformedCreateView = false
| mRemoving = false
| mRestored = false
| mRetainInstance = false
| mRetaining = false
| mSavedFragmentState = null
| mSavedViewState = null
| mState = 0
| mTag = null
| mTarget = null
| mTargetIndex = -1
| mTargetRequestCode = 0
| mUserVisibleHint = true
| mView = null
| mWho = null
| shadow$_klass_ = android.arch.lifecycle.ReportFragment
| shadow$_monitor_ = 0
* Excluded Refs:
| Field: android.os.Message.obj
| Field: android.os.Message.next
| Field: android.os.Message.target
| Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
| 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)
Reopening because we can document a gist that uses reflection to fix this:
Latest ViewGroup sources: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewGroup.java
This leaks happens whenever ViewGroup.ViewLocationHolder.recycle() is called (a ViewLocationHolder instance is cleared incorrectly then put back in the static pool) , which AFAIK only happens from ViewGroup.ChildListForAccessibility.init() (is that true?), which is called when ViewGroupChildListForAccessibility. obtain is called with sort set to true.
In other words, as far as I can see, ViewGroup.ViewLocationHolder is only ever used as a temporary object to sort the list of children in ViewGroup.ChildListForAccessibility, once per ViewGroup.ChildListForAccessibility.obtain() call.
That happens in ViewGroup.addChildrenForAccessibility and ViewGroup.dispatchPopulateAccessibilityEventInternal.
Here's an idea:
Reopening because we can document a gist that uses reflection to fix this:
Here's an idea:
- a) clear the ViewGroup$ViewLocationHolder.mRoot ref for all instances in the array
Took a stab at this, in ActivityRefWatcher:
private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
new ActivityLifecycleCallbacksAdapter() {
@Override public void onActivityDestroyed(Activity activity) {
System.out.println("API level = " + Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
Class<?> holder = Class.forName("android.view.ViewGroup$ViewLocationHolder");
// class ViewLocationHolder {
// SynchronizedPool<ViewLocationHolder> sPool;
Field sPoolField = holder.getDeclaredField("sPool");
sPoolField.setAccessible(true);
Object sPool = sPoolField.get(null);
// class SynchronizedPool<T> extends SimplePool<T>
Class<?> simplePoolClass = sPool.getClass().getSuperclass();
// class SimplePool<T> implements Pool<T> {
// Object[] mPool;
// int mPoolSize;
Field poolArrayField = simplePoolClass.getDeclaredField("mPool");
poolArrayField.setAccessible(true);
Object[] poolArray = (Object[]) poolArrayField.get(sPool);
Field poolSizeField = simplePoolClass.getDeclaredField("mPoolSize");
poolSizeField.setAccessible(true);
int poolSize = (int) poolSizeField.get(sPool);
// sanity check, we really care about poolSize
int poolArrayLength = Array.getLength(poolArray);
System.out.println("poolArrayLength = " + poolArrayLength);
for (int i = 0; i < poolArrayLength; i++) {
Object viewLocationHolder = poolArray[i];
if (viewLocationHolder == null) {
System.out.println("poolArray[" + i + "] == null");
continue;
}
Field mRootField = viewLocationHolder.getClass().getDeclaredField("mRoot");
mRootField.setAccessible(true);
Object mRoot = mRootField.get(viewLocationHolder);
if (mRoot == null) {
System.out.println("poolArray[" + i + "].mRoot == null");
} else {
System.out.println("Found leak! poolArray[" + i + "].mRoot != null");
}
}
System.out.println("poolSize = " + poolSize);
for (int i = 0; i < poolSize; i++) {
Object viewLocationHolder = poolArray[i];
// class ViewLocationHolder {
// ViewGroup mRoot;
Field mRootField = viewLocationHolder.getClass().getDeclaredField("mRoot");
mRootField.setAccessible(true);
// release leaked reference
mRootField.set(viewLocationHolder, null);
}
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
// we tried...
System.out.println(e);
}
}
refWatcher.watch(activity);
}
};
On API 28, attempting to access ViewGroup$ViewLocationHolder.sPool throws a NoSuchFieldException.
2019-01-11 12:30:56.723 31998-31998/com.squareup.cash.beta.debug W/cash.beta.debu: Accessing hidden field Landroid/view/ViewGroup$ViewLocationHolder;->sPool:Landroid/util/Pools$SynchronizedPool; (dark greylist, reflection)
More here: https://developer.android.com/about/versions/pie/restrictions-non-sdk-interfaces.
Given this is a leak in AOSP, should we file a feature request to move the pertinent classes to the light greylist?
Unfortunate bad luck!
I have a similar problem, but the solution above did not help me.
https://stackoverflow.com/questions/54713082/android-leakcanary-from-object-0-after-transition-animation
Is there any way to suppress the LeakCanary notification for this individual type of leak? I know it's a real issue, and LeakCanary reporting it means that LeakCanary is doing its job correctly. However, because we have no control over fixing it, being notified every time it happens isn't particularly useful. The other alternative would be to disable LeakCanary entirely for the app which would be throwing out the baby with the bathwater.
Edit: I see there is AndroidExcludedRefs.java. Seems like this leak should be included in the list.
Edit2: This leak is included in AndroidExcludedRefs.java, but it is not alwaysExclude()'d. Using the following code also still triggers memory leaks. Is this a valid way to exclude leaks? If so, I'll unfortunately have to disable LeakCanary on Android P.
package com.squareup.leakcanary
import android.app.Application
import com.squareup.leakcanary.AndroidExcludedRefs.VIEWLOCATIONHOLDER_ROOT
fun buildAndInstallLeakCanary(app: Application) {
val excludedRefsBuilder: ExcludedRefs.Builder = ExcludedRefs.builder()
AndroidExcludedRefs
.values()
.filter { it.applies }
.forEach { ref ->
if (ref == VIEWLOCATIONHOLDER_ROOT) {
excludedRefsBuilder
.instanceField("android.view.ViewGroup\$ViewLocationHolder", "mRoot")
.alwaysExclude()
.staticField("android.view.ViewGroup\$ViewLocationHolder", "sPool")
.alwaysExclude()
} else {
ref.add(excludedRefsBuilder)
}
(excludedRefsBuilder as ExcludedRefs.BuilderWithParams).named(ref.name)
}
LeakCanary.refWatcher(app)
.excludedRefs(excludedRefsBuilder.build())
.buildAndInstall()
}
@jrodbx Have you filed a feature request to move the relevant classes to the light greylist? If so, please link it, as I'd like to follow the status of this feature request.
@AOrobator you should rarely if ever have to use "always exclude", that's only for things like weak references.
LeakCanary cannot "ignore" a leak until it knows what leak this is. Then it'll show up as an "excluded" leak and that's as good as it gets.
In the meantime, I believe we can come up with a fix that doesn't involve reflection, if someone is interested in having some fun.
This leak is triggered when ViewGroup#addChildrenForAccessibility is called, the view group ends up leaking in ViewLocationHolder.sPool.
So one way to "clean this up" is to create a dummy view group, keep it detached, add ViewLocationHolder.MAX_POOL_SIZE children (32) to it, then call ViewGroup#addChildrenForAccessibility on it. This will effectively reset the pool so that all instances leaks the dummy view group as their mRoot.
This may be expansive, it's worth measuring it.
I've just quickly tried next code:
class AndroidPHackCleanReference {
companion object {
fun execute(activity: AppCompatActivity) {
val viewGroup = LinearLayout(activity)
// 32 - ViewLocationHolder.MAX_POOL_SIZE
for (i in 0..32) {
viewGroup.addView(TextView(activity))
}
viewGroup.addChildrenForAccessibility(ArrayList(viewGroup.childViews))
}
}
}
And I still see this leak in the Leak Canary (I need a button now to trigger the analysis to not click app to pass threshold).
My understanding - View has context as a constructor parameter, this still leak activity since I will use current activity to construct views.
@emartynov The button (notification) will be coming in the next alpha :) . In the meantime, press "home" (not back) and that will trigger the heap dump (triggers on app background)
Edit: programmers make mistakes, whether they work at Google or not. Let's not pile on this, although I get the frustration :) .
Also, do you have a short piece of code that reproduces the issue?
@pyricau I think I found a pattern to reproduce the related issues: Open a DialogFragment from a Fragment, then press 'Current App' button (the Square button on NavigationBar), then press it again to bring everything to normal, then press 'Back' button until the App is closed.
I can always reproduce this on my LG G7 running Android 9, but not always for AVD with Android 9 or 10. Details below:
TestLeakFragment.kt
```kotlin TestLeakFragment.kt
class TestFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val frame = FrameLayout(inflater.context)
frame.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
val button = AppCompatButton(inflater.context)
button.layoutParams =
FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
.also {
it.gravity = Gravity.CENTER
}
frame.addView(button)
button.text = "Click here!"
button.setOnClickListener {
TestDialogFragment().show(childFragmentManager, "test")
}
return frame
}
}
class TestDialogFragment : AppCompatDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return Button(inflater.context)
}
}
</details>
<details>
<summary>activity_debug.xml</summary>
```xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<fragment
android:id="@+id/debugContainer"
android:name="kohii.v1.sample.ui.debug.TestFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
DevActivity.kt
class DevActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_debug)
}
}
Logcat
2019-11-07 22:30:35.828 18199-18199/kohii.v1.sample.dev D/LeakCanary: Installing AppWatcher
2019-11-07 22:30:44.265 18199-18199/kohii.v1.sample.dev D/LeakCanary: Watching instance of android.widget.Button with key e568fe83-59e8-4c79-91ae-a018a9e7df4e
2019-11-07 22:30:44.266 18199-18199/kohii.v1.sample.dev D/LeakCanary: Watching instance of kohii.v1.sample.ui.debug.TestDialogFragment with key 7cb87876-cf05-4b1a-b9ee-af12446c16e7
2019-11-07 22:30:45.773 18199-18199/kohii.v1.sample.dev D/LeakCanary: Already scheduled retained check, ignoring (app became invisible)
2019-11-07 22:30:45.777 18199-18199/kohii.v1.sample.dev D/LeakCanary: Watching instance of androidx.lifecycle.ReportFragment with key 7d73525c-097f-4664-aeb0-4fc5cc1390ce
2019-11-07 22:30:45.778 18199-18199/kohii.v1.sample.dev D/LeakCanary: Watching instance of kohii.v1.sample.DevActivity with key dd11f52d-374c-48e8-9c86-649ed295ccf5
2019-11-07 22:30:45.779 18199-18199/kohii.v1.sample.dev D/LeakCanary: Watching instance of android.widget.FrameLayout with key 820ab904-6a6e-4120-9b48-122dd4adf8b8
2019-11-07 22:30:45.781 18199-18199/kohii.v1.sample.dev D/LeakCanary: Watching instance of kohii.v1.sample.ui.debug.TestFragment with key 137ab2cd-5cc6-4d65-849b-c395ee8b6e61
2019-11-07 22:30:46.650 18199-18328/kohii.v1.sample.dev D/LeakCanary: Checking retained object because app became invisible
2019-11-07 22:30:46.651 18199-18328/kohii.v1.sample.dev D/LeakCanary: No retained objects
2019-11-07 22:30:49.294 18199-18199/kohii.v1.sample.dev D/LeakCanary: Already scheduled retained check, ignoring (found new object retained)
2019-11-07 22:30:49.295 18199-18328/kohii.v1.sample.dev D/LeakCanary: Checking retained object because found new object retained
2019-11-07 22:30:49.488 18199-18328/kohii.v1.sample.dev D/LeakCanary: Found 2 retained objects, which is less than the visible threshold of 5
2019-11-07 22:30:50.810 18199-18199/kohii.v1.sample.dev D/LeakCanary: Already scheduled retained check, ignoring (found new object retained)
2019-11-07 22:30:50.811 18199-18199/kohii.v1.sample.dev D/LeakCanary: Already scheduled retained check, ignoring (found new object retained)
2019-11-07 22:30:51.551 18199-18328/kohii.v1.sample.dev D/LeakCanary: Checking retained object because Showing retained objects notification
2019-11-07 22:30:51.759 18199-18328/kohii.v1.sample.dev D/LeakCanary: Found 6 retained references, dumping the heap
2019-11-07 22:30:51.795 18199-18328/kohii.v1.sample.dev D/LeakCanary: Removing 1 heap dumps
2019-11-07 22:30:57.226 18199-18350/kohii.v1.sample.dev D/LeakCanary: Analysis in progress, working on: PARSING_HEAP_DUMP
2019-11-07 22:30:58.484 18199-18350/kohii.v1.sample.dev D/LeakCanary: Analysis in progress, working on: FINDING_LEAKING_INSTANCES
2019-11-07 22:30:59.613 18199-18350/kohii.v1.sample.dev D/LeakCanary: Analysis in progress, working on: FINDING_PATHS_TO_LEAKING_INSTANCES
2019-11-07 22:31:05.526 18199-18350/kohii.v1.sample.dev D/LeakCanary: Analysis in progress, working on: FINDING_DOMINATORS
2019-11-07 22:31:05.575 18199-18350/kohii.v1.sample.dev D/LeakCanary: Analysis in progress, working on: COMPUTING_NATIVE_RETAINED_SIZE
2019-11-07 22:31:05.878 18199-18350/kohii.v1.sample.dev D/LeakCanary: Analysis in progress, working on: COMPUTING_RETAINED_SIZE
2019-11-07 22:31:05.907 18199-18350/kohii.v1.sample.dev D/LeakCanary: Analysis in progress, working on: BUILDING_LEAK_TRACES
2019-11-07 22:31:05.919 18199-18350/kohii.v1.sample.dev D/LeakCanary: Analysis in progress, working on: REPORTING_HEAP_ANALYSIS
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: HeapAnalysisSuccess(heapDumpFile=/storage/emulated/0/Download/leakcanary-kohii.v1.sample.dev/2019-11-07_22-30-51_803.hprof, createdAtTimeMillis=1573133465921, analysisDurationMillis=8696, applicationLeaks=[], libraryLeaks=[LibraryLeak(className=kohii.v1.sample.DevActivity, leakTrace=
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β¬
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ android.view.ViewGroup$ViewLocationHolder
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: NO (a class is never leaking)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β GC Root: System class
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β static ViewGroup$ViewLocationHolder.sPool
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β ~~~~~
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ android.util.Pools$SynchronizedPool
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: UNKNOWN
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β Pools$SynchronizedPool.mPool
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β ~~~~~
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ java.lang.Object[]
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: UNKNOWN
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β array Object[].[0]
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β ~~~
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ android.view.ViewGroup$ViewLocationHolder
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: UNKNOWN
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β ViewGroup$ViewLocationHolder.mRoot
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β ~~~~~
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ androidx.appcompat.widget.FitWindowsFrameLayout
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: YES (View.mContext references a destroyed activity)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β mContext instance of android.view.ContextThemeWrapper, wrapping activity kohii.v1.sample.DevActivity with mDestroyed = true
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View#mParent is set
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View#mAttachInfo is null (view detached)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View.mWindowAttachCount = 1
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β FitWindowsFrameLayout.mContext
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ android.view.ContextThemeWrapper
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: YES (FitWindowsFrameLayoutβ is leaking and ContextThemeWrapper wraps an Activity with Activity.mDestroyed true)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β ContextThemeWrapper.mBase
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β°β kohii.v1.sample.DevActivity
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: YES (ContextThemeWrapperβ is leaking and Activity#mDestroyed is true and ObjectWatcher was watching this)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β key = dd11f52d-374c-48e8-9c86-649ed295ccf5
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β watchDurationMillis = 5981
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β retainedDurationMillis = 948
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: , retainedHeapByteSize=11812, pattern=instance field android.view.ViewGroup$ViewLocationHolder#mRoot, description=In Android P, ViewLocationHolder has an mRoot field that is not cleared in its clear() method. Introduced in https://github.com/aosp-mirror/platform_frameworks_base/commit/86b326012813f09d8f1de7d6d26c986a909d Bug report: https://issuetracker.google.com/issues/112792715), LibraryLeak(className=android.widget.Button, leakTrace=
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β¬
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ android.view.ViewGroup$ViewLocationHolder
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: NO (a class is never leaking)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β GC Root: System class
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β static ViewGroup$ViewLocationHolder.sPool
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β ~~~~~
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ android.util.Pools$SynchronizedPool
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: UNKNOWN
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β Pools$SynchronizedPool.mPool
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β ~~~~~
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ java.lang.Object[]
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: UNKNOWN
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β array Object[].[0]
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β ~~~
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ android.view.ViewGroup$ViewLocationHolder
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: UNKNOWN
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β ViewGroup$ViewLocationHolder.mRoot
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β ~~~~~
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ androidx.appcompat.widget.FitWindowsFrameLayout
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: YES (View.mContext references a destroyed activity)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β mContext instance of android.view.ContextThemeWrapper, wrapping activity kohii.v1.sample.DevActivity with mDestroyed = true
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View#mParent is set
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View#mAttachInfo is null (view detached)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View.mWindowAttachCount = 1
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β FitWindowsFrameLayout.mChildren
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ android.view.View[]
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: YES (FitWindowsFrameLayoutβ is leaking)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β array View[].[0]
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ androidx.appcompat.widget.ContentFrameLayout
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: YES (View[]β is leaking and View.mContext references a destroyed activity)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β mContext instance of android.view.ContextThemeWrapper, wrapping activity kohii.v1.sample.DevActivity with mDestroyed = true
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View#mParent is set
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View#mAttachInfo is null (view detached)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View.mWindowAttachCount = 1
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β ContentFrameLayout.mChildren
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: ββ android.view.View[]
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: YES (ContentFrameLayoutβ is leaking)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β β array View[].[0]
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β°β android.widget.Button
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β Leaking: YES (View[]β is leaking and View.mContext references a destroyed activity and ObjectWatcher was watching this)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β mContext instance of android.view.ContextThemeWrapper, wrapping activity kohii.v1.sample.DevActivity with mDestroyed = true
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View#mParent is set
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View#mAttachInfo is null (view detached)
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β View.mWindowAttachCount = 1
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β key = e568fe83-59e8-4c79-91ae-a018a9e7df4e
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β watchDurationMillis = 7494
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: β retainedDurationMillis = 2467
2019-11-07 22:31:05.924 18199-18350/kohii.v1.sample.dev D/LeakCanary: , retainedHeapByteSize=17473, pattern=instance field android.view.ViewGroup$ViewLocationHolder#mRoot, description=In Android P, ViewLocationHolder has an mRoot field that is not cleared in its clear() method. Introduced in https://github.com/aosp-mirror/platform_frameworks_base/commit/86b326012813f09d8f1de7d6d26c986a909d Bug report: https://issuetracker.google.com/issues/112792715)])
Anyone has any update about this leak. Google has locked the issue tracker thread and leak has been happening a lot on my app. :(
I found the same problem in Android P
Good news! I managed to reproduce the leak here: https://github.com/square/leakcanary/pull/1842
Then I applied a fix: d3769b1cd9392ff05c2f8572bf9c331bd238abcd and it's working!
The next release of LeakCanary will include a separate artifact that can fix leaks for you, automatically, so ideally I can ship this fix as well.
The main thing to figure out is when to apply it. Fragment destroy? Activity destroy? Every time a view is detached?
big thanks to @jrodbx (for the reflection code which I used to quickly detect if there was a leak / if the fix was working), @eneim for the repro code, and @emartynov for the almost working fix that involves no reflection.
@pyricau, that was a big surprise for me this morning. I completely forgot about this and super busy with my current job change that I don't participate in the open-source much (unfortunately).
To be honest, the biggest part of this code I took from @swankjesse somewhere online and just a bit improved it later (if I remember it correctly).
Thank you again for such a great library. Looking forward to the new release.
ππ»
Most helpful comment
Thanks, found the mail. If someone is wondering: