2

I'm currently using Android Studio to develop live wallpapers using the wallpaper service.

As a result of the verification, it was found that a memory leak occurs and disappear(?) when the following operations are executed, but I do not know the solution.

How can I resolve a memory leak?

  1. Run activity (If there is no Activity with android.intent.category.LAUNCHER set, in my case Leak Canary will start.) , and close.
  2. Set my livewallpaper to Home screen and Lock Screen , and close.(the background will be black.)
  3. Start new profiler session in Android Studio to check memory.
  4. Set other wallpaper(ex. Solid colors) to Home screen and Lock Screen , and close.(the background will change)

Leak Canary detects and notifies you of leaks.(The data dumped at this point will be described later) You can also check that Memory remains in Profiler.

But if I ignore the notification, start Leak Canary and just close it, the memory profiler goes to 0 and stops.

If you select the previously displayed Leak Canary notification, you will see the following text: 「All retained objects were garbage collected Tap to dismiss」

Wallpaper.java

package Wallpaper;

import android.service.wallpaper.WallpaperService;
import android.util.Log;
public class Wallpaper extends WallpaperService{
    @Override
    public Engine onCreateEngine() {
        return new Engine();
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.wallpapertest">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.WallpaperTest">
<!--        <activity-->
<!--            android:name=".MainActivity"-->
<!--            android:label="@string/app_name"-->
<!--            android:theme="@style/Theme.WallpaperTest.NoActionBar">-->
<!--            <intent-filter>-->
<!--                <action android:name="android.intent.action.MAIN" />-->
<!--                <category android:name="android.intent.category.LAUNCHER" />-->
<!--            </intent-filter>-->
<!--        </activity>-->
        <service
            android:name="Wallpaper"
            android:label="TestWallpaper"
            android:permission="android.permission.BIND_WALLPAPER">
            <intent-filter>
                <action android:name="android.service.wallpaper.WallpaperService" />
            </intent-filter>
            <meta-data
                android:name="android.service.wallpaper"
                android:resource="@xml/wallpaper" />
        </service>

    </application>
</manifest>

dumped by Leak Canary


┬───
│ GC Root: Global variable in native code
│
├─ android.service.wallpaper.WallpaperService$IWallpaperEngineWrapper instance
│    Leaking: UNKNOWN
│    Retaining 614 B in 3 objects
│    this$0 instance of com.example.wallpapertest.Wallpaper
│    ↓ WallpaperService$IWallpaperEngineWrapper.this$0
│                                               ~~~~~~
╰→ com.example.wallpapertest.Wallpaper instance
​     Leaking: YES (ObjectWatcher was watching this because com.example.
​     wallpapertest.Wallpaper received Service#onDestroy() callback)
​     Retaining 1.4 kB in 16 objects
​     key = 258eebec-e068-4a18-8b80-f4044dd74ca4
​     watchDurationMillis = 17673
​     retainedDurationMillis = 11652
​     mApplication instance of android.app.Application
​     mBase instance of android.app.ContextImpl

METADATA

Build.VERSION.SDK_INT: 30
Build.MANUFACTURER: Google
LeakCanary version: 2.6
App process name: com.example.wallpapertest
Stats: LruCache[maxSize=3000,hits=1850,misses=54308,hitRate=3%]
RandomAccess[bytes=2722909,reads=54308,travel=19446709706,range=16694011,size=22
214598]
Heap dump reason: user request
Analysis duration: 634134 ms

build.gradle(:app)

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.wallpapertest"
        minSdkVersion 28
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        //for LeakCanary
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArgument "listener", "leakcanary.FailTestOnLeakRunListener"

    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    buildFeatures {
        viewBinding true
    }
}

dependencies {
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'androidx.navigation:navigation-fragment:2.3.5'
    implementation 'androidx.navigation:navigation-ui:2.3.0'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    //for LeakCanary
    def leakcanary_version = '2.6'
    debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakcanary_version"
    androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanary_version"
}

Other

  • Android Studio 4.2.1
  • AVD Pixel3a API30(Android11)
  • Clicking on the profiler's memory graph causes an IDE internal error, so I can't see the details.
  • % java --version
    openjdk 11.0.8 2020-07-14
    OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    OpenJDK 64-Bit Server VM (build 11.0.8+10-b944.6916264, mixed mode)

I suspect the Wallpaper Service has some reference. I created another activity as a trial, executed 1-4, checked for a memory leak, and then opened and closed the created activity, and the leak disappeared.

I'm beginner so ,would very much like to hear what you have to say. Any ideas or suggestions would be welcome.

Profiler Image [1]: https://i.stack.imgur.com/wQvts.png

Add: Apparently, starting an activity other than LeakCanary resolves the leak. This is an Android spec and may not be a memory leak.

Fuji
  • 21
  • 3

0 Answers0