2

folks

Using leakcanary tool we have noticed recently memory leaks in activities that use webview. The issue just occurs in some models like Samsung devices with Android 13 (one ui 5). We were not able to reproduce the issue in Pixel 4 with Android 13. When the user closes the activity it still in memory even after onDestroy. We have noticed an increase in ANRs to the affected devices.

The Android code to reproduce the issue and leakcanary`s report are bellow. (We just have to inflate a layout that has webview and close the activity, so the memory leak happens)

AndroidManifest.xml

<activity
 android:name=".HomeActivity"
 android:exported="false"
 android:theme="@style/AppTheme.NoActionBar">
</activity> 

activity_home.xml (Here we have the tag for webview component)

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/main"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context="br.com.gabba.myapp.presentation.WebViewActivity"
 tools:viewBindingIgnore="true">
 <com.google.android.material.appbar.AppBarLayout
 android:id="@+id/appBarLayout"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:theme="@style/AppTheme.AppBarOverlay"
 android:background="@drawable/bg_header"
 android:gravity="bottom"
 app:elevation="0dp">
 <androidx.appcompat.widget.Toolbar
 android:id="@+id/toolbar"
 android:layout_width="match_parent"
 android:layout_height="?attr/actionBarSize"
 android:paddingStart="8dp"
 app:contentInsetLeft="0dp"
 app:contentInsetStart="0dp"
 app:contentInsetStartWithNavigation="0dp"
 app:popupTheme="@style/AppTheme.PopupOverlay"
 app:title="@string/app_name"
 app:titleTextAppearance="@style/Toolbar.TitleTextExterno" />
 </com.google.android.material.appbar.AppBarLayout>
 <FrameLayout
 android:id="@+id/frameLayout"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 app:layout_behavior="@string/appbar_scrolling_view_behavior">
 <WebView
 android:id="@+id/webview"
 android:layout_width="match_parent"
 android:layout_height="match_parent" />
 </FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

HomeActivity.kt - All we need to have the issue is inflate the layout with the webview.

package br.com.gabba.myapp.presentation
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import br.com.gabba.myapp.R
class HomeActivity : AppCompatActivity() {
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_home)
 }
}

app/build.gradle

(...)
implementation 'androidx.activity:activity-ktx:1.6.1'
(...)
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'

LeakCanary documentation

LeakCanary report with the issue:

 │ GC Root: Global variable in native code
 │
 ├─ J1 instance
 │ Leaking: UNKNOWN
 │ Retaining 137,3 kB in 1971 objects
 │ ↓ WindowAndroid.p
 │ ~
 ├─ b30 instance
 │ Leaking: UNKNOWN
 │ Retaining 136,2 kB in 1930 objects
 │ ↓ b30.b
 │ ~
 ├─ com.android.internal.policy.PhoneWindow instance
 │ Leaking: YES (Window#mDestroyed is true)
 │ Retaining 136,2 kB in 1929 objects
 │ mContext instance of br.com.gabba.myapp.presentation.HomeActivity with mDestroyed = true
 │ mOnWindowDismissedCallback instance of br.com.gabba.myapp.presentation.HomeActivity with mDestroyed = true
 │ ↓ Window.mContext
 ╰→ br.com.gabba.myapp.presentation.HomeActivity instance
 ​ Leaking: YES (ObjectWatcher was watching this because br.com.gabba.myapp.presentation.HomeActivity received
 ​ Activity#onDestroy() callback and Activity#mDestroyed is true)
 ​ Retaining 6,8 kB in 245 objects
 ​ key = afa4c248-0006-4b43-9660-d2131e74893a
 ​ watchDurationMillis = 8817
 ​ retainedDurationMillis = 3814
 ​ mApplication instance of br.com.gabba.myapp.myappApplication
 ​ mBase instance of androidx.appcompat.view.ContextThemeWrapper
 
 METADATA
 
 Build.VERSION.SDK_INT: 33
 Build.MANUFACTURER: samsung
 LeakCanary version: 2.10
 App process name: br.com.gabba.myapp
 Class count: 29960
 Instance count: 230083
 Primitive array count: 152647
 Object array count: 33977
 Thread count: 72
 Heap total bytes: 32257183
 Bitmap count: 7
 Bitmap total bytes: 5674439
 Large bitmap count: 0
 Large bitmap total bytes: 0
 Db 1: closed /data/user/0/br.com.gabba.myapp/databases/google_app_measurement_local.db
 Db 2: open /data/user/0/br.com.gabba.myapp/databases/leaks.db
 Db 3: open /data/user/0/br.com.gabba.myapp/databases/com.microsoft.appcenter.persistence
 Db 4: open /data/user/0/br.com.gabba.myapp/no_backup/androidx.work.workdb
 Db 5: open /data/user/0/br.com.gabba.myapp/databases/com.google.android.datatransport.events
 Stats: LruCache[maxSize=3000,hits=119796,misses=220169,hitRate=35%]
 RandomAccess[bytes=11094589,reads=220169,travel=116557590219,range=37155332,size=47075038]
 Analysis duration: 10730 ms
 
asked Mar 13, 2023 at 15:38
5
  • you have to remove webiview from memory into onDestroy event in HomeActivity, try this post: stackoverflow.com/questions/17418503/destroy-webview-in-android Commented Mar 13, 2023 at 16:48
  • We are having the same issue and still looking for a solution. Commented Mar 14, 2023 at 1:40
  • @drbf we can ask for help from the leakcanary guys. They are usually pretty good at pointing engineers in the right direction. Commented Mar 14, 2023 at 1:46
  • @PaolinoLAngeletti, Thank you. Putting this - webView.destroy(); - on activity ondestroy method seems to solve the issue. Commented Mar 15, 2023 at 16:13
  • @DmytroKarataiev, You should try to put this - webView.destroy(); - on activity ondestroy method. It worked in my project. Commented Mar 15, 2023 at 16:14

1 Answer 1

1

Thanks to @PaolinoLAngeletti comment we figure out that putting this line - - webView.destroy(); - on activity ondestroy method seems to solve the issue.

 (...)
 
 this.webView = findViewById(R.id.webview); //get a reference to webview
 
 (...)
@Override
 protected void onDestroy() {
 
 try {
 
 if (webView != null) {
 webView.setWebViewClient(null);
 webView.setWebChromeClient(null);
 webView.clearHistory();
 webView.clearCache(true);
 webView.destroy(); //this was added
 webview = null;
 }
 } catch (Exception e) {
 Log.e(TAG, "onDestroy", e);
 }
 
 super.onDestroy();
 }
answered Mar 15, 2023 at 16:25
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.