默认动态壁纸服务在 Android 中泄漏内存

问题描述

我目前正在使用 Android Studio 使用壁纸服务开发动态壁纸。

经过验证,发现在执行以下操作时出现内存泄漏并消失(?),但不知道解决方案。

如何解决内存泄漏?

  1. 运行活动 (如果没有设置 android.intent.category.LAUNCHER 的 Activity,在我的情况下 Leak Canary 将启动。) ,然后关闭
  2. 将我的动态壁纸设置为“主屏幕”和“锁定屏幕”,然后关闭。(背景将为黑色。)
  3. 在 Android Studio 中启动新的分析器会话以检查内存。
  4. 将其他壁纸(例如纯色)设置为主屏幕和锁定屏幕,然后关闭。(背景会改变)

Leak Canary 检测并通知您泄漏。(此时转储的数据将在后面描述) 您还可以检查内存是否保留在 Profiler 中。

但如果我忽略通知,启动 Leak Canary 并关闭它,内存分析器会变为 0 并停止。

如果您选择之前显示的 Leak Canary 通知,您将看到以下文本: 「所有保留的对象都被垃圾收集了点击即可关闭

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>

被 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"
}

其他

  • Android Studio 4.2.1
  • AVD Pixel3a API30(Android11)
  • 单击分析器的内存图会导致 IDE 内部错误,因此我看不到详细信息。
  • % java --version
    openjdk 11.0.8 2020-07-14
    OpenJDK 运行时环境(构建 11.0.8+10-b944.6916264)
    OpenJDK 64 位服务器 VM(构建 11.0.8+10-b944.6916264,混合模式)

我怀疑墙纸服务有一些参考。 我创建了另一个activity作为试用,执行了1-4,检查了内存泄漏,然后打开关闭创建的activity,泄漏消失了。

我是初学者,非常想听听您的意见。欢迎提出任何想法或建议。

分析器图像 [1]:https://i.stack.imgur.com/wQvts.png

添加: 显然,启动 LeakCanary 以外的活动可以解决泄漏问题。 这是 Android 规范,可能不是内存泄漏。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...