【问题标题】:Memory leak with simple activities navigation带有简单活动导航的内存泄漏
【发布时间】:2016-09-20 02:40:09
【问题描述】:

我目前正在开发一个 Xamarin.Android 应用程序,该应用程序包含大量活动,使用返回图像的 API,有时还会返回大量对象列表,因此我必须注意内存以避免 OOM。

但是,当我开始使用位图时,我终于设法拥有了一些。起初,我以为是因为那些位图,所以我进行了一些测试。它似乎不是。我停用了 API,所以我使用的是空的对象列表,没有图像。而且我仍然设法让我的应用程序内存使用变得疯狂,最终崩溃。

由于我无法在 Visual Studio 上安装 Xamarin Profiler(不知道为什么,但不是这里的主要问题),我在我的设备(它是 OnePlus One)上安装了一个名为 Intel Performance Viewer 的应用程序,即能够实时监控设备的RAM使用情况。我启动我的应用程序,假设我的 2GB 总内存中的内存使用量为 1.1GB。我单击了一个应该显示对象列表的按钮,但随着 API 关闭,列表为空。因此,该活动包含一个自定义应用栏、两个按钮、一个空列表视图和一个显示“列表为空”的文本。 RAM 消耗从调用此活动的大约 30MB 上升。然后我按下返回按钮,它正在调用 Finish();在活动上,然后我回到主要的。 RAM 消耗从 1 或 2 MB 下降。

然后,如果我再次进行该活动,它将开始,多吃 30 MB,如果我继续在这样的活动之间切换,它最终会导致 OOME。

我尝试在我的设备开发人员选项中选中“不要保留活动”,它似乎释放了更多 RAM(多么合乎逻辑),但仍然不是全部。我必须在内存不足之前进行更多切换,但问题仍然存在。

Finish 不应该将活动中包含的所有数据都放入垃圾收集器中吗?我试着做 GC.Collect();在我的 OnDestroy 中,没有效果。

我不知道我是否误解了内存在 android 上的工作方式,因为我对移动开发相当陌生,但这让我很头疼。有什么帮助吗?

谢谢!

编辑:这是我在 OOM 时得到的。

    05-23 10:15:37.973 D/dalvikvm( 5049): GC_FOR_ALLOC freed 1587K, 3% free 248825K/256263K, paused 22ms, total 23ms
05-23 10:15:37.973 I/dalvikvm-heap( 5049): Grow heap (frag case) to 245.840MB for 2908172-byte allocation
05-23 10:15:38.029 D/dalvikvm( 5049): GC_CONCURRENT freed 127K, 2% free 2515
37K/256263K, paused 10ms+10ms, total 52ms
05-23 10:15:38.077 D/dalvikvm( 5049): GC_FOR_ALLOC freed 74K, 2% free 251463K/256263K, paused 23ms, total 23ms
05-23 10:15:38.077 I/dalvikvm-heap( 5049): Forcing collection of SoftReferences for 11632652-byte allocation
05-23 10:15:38.105 D/dalvikvm( 5049): GC_BEFORE_OOM freed 306K, 2% free 251156K/256263K, paused 29ms, total 29ms
05-23 10:15:38.105 E/dalvikvm-heap( 5049): Out of memory on a 11632652-byte allocation.
05-23 10:15:38.105 I/dalvikvm( 5049): "main" prio=5 tid=1 RUNNABLE
05-23 10:15:38.105 I/dalvikvm( 5049):   | group="main" sCount=0 dsCount=0 obj=0xa62704b0 self=0xb7c7b510
05-23 10:15:38.105 I/dalvikvm( 5049):   | sysTid=5049 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1217084352
05-23 10:15:38.105 I/dalvikvm( 5049):   | schedstat=( 7886788399 5740305249 19539 ) utm=596 stm=192 core=0
05-23 10:15:38.117 E/mono-rt ( 5049): =================================================================
05-23 10:15:38.117 E/mono-rt ( 5049): Got a SIGSEGV while executing native code. This usually indicates
05-23 10:15:38.117 E/mono-rt ( 5049): a fatal error in the mono runtime or one of the native libraries 
05-23 10:15:38.117 E/mono-rt ( 5049): used by your application.
05-23 10:15:38.117 E/mono-rt ( 5049): =================================================================
05-23 10:15:38.117 E/mono-rt ( 5049): 
05-23 10:15:38.117 F/libc    ( 5049): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 5049

【问题讨论】:

    标签: android memory-leaks xamarin xamarin.android


    【解决方案1】:

    我建议你阅读这篇关于:


    编辑:

    试试这样的:

    using Android.Content;
    using Java.IO;
    using System;
    
    namespace SampleTest.Droid
    {
        public class CacheManager
        {
            private static long MaxSize = 5242880L; // 5MB
    
            private CacheManager() { }
    
            public static void CacheData(Context context, Byte[] data, String name)
            {
                try
                {
                    File cacheDir = context.CacheDir;
                    long size = cacheDir.TotalSpace;
                    long newSize = data.Length + size;
    
                    if (newSize > MaxSize)
                    {
                        CleanDir(cacheDir, newSize - MaxSize);
                    }
    
                    File file = new File(cacheDir, name);
                    FileOutputStream OS = new FileOutputStream(file);
    
                    try
                    {
                        OS.Write(data);
                    }
                    catch (Exception ex)
                    {
                        OS.Flush();
                        OS.Close();
                        System.Console.WriteLine(ex.Message);
                        throw;
                    }
                }
                catch (IOException ex)
                {
                    System.Console.WriteLine(ex.Message);
                    throw;
                }
            }
    
            private static void CleanDir(File dir, long bytes)
            {
                long bytesDeleted = 0;
                File[] files = dir.ListFiles();
    
                foreach (File file in files)
                {
                    bytesDeleted += file.Length();
                    file.Delete();
    
                    if (bytesDeleted >= bytes)
                        break;
                }
            }
    
            public static byte[] RetrieveData(Context context, String name)
            {
                try
                {
    
                    File cacheDir = context.CacheDir;
                    File file = new File(cacheDir, name);
    
                    if (!file.Exists())
                    {
                        // Data doesn't exist
                        return null;
                    }
    
                    byte[] data = new byte[(int)file.Length()];
                    FileInputStream fis = new FileInputStream(file);
                    try
                    {
                        fis.Read(data);
                    }
                    finally
                    {
                        fis.Close();
                    }
                    return data;
                }
    
                catch (Exception ex)
                {
                    System.Console.WriteLine(ex.Message);
                    throw;
                }
            }
    
            private static long DirSize(File Dir)
            {
                long size = 0;
                File[] files = Dir.ListFiles();
    
                foreach (File file in files)
                {
                    if (file.IsFile)
                        size += file.Length();
                }
                return size;
            }
        }
    }
    

    参考:https://stackoverflow.com/a/10069679/3891036

    【讨论】:

    • 我已经阅读了其中的一些内容,我从中了解到(也许我错了),当一个活动完成后,它仍然保留在内存中以便更快地重新启动它,但会可用内存不足时释放。但这似乎永远不会发生,内存会上升,直到达到最大堆大小。当我得到那个 OOM 时,我会添加一些堆栈跟踪。
    【解决方案2】:

    用片段替换活动。活动很繁重,我猜你正在继续在导航上创造新的活动。 在您知道事情会很容易失控并且您的应用程序将达到 OOM 阈值之前。保留单个活动并在其中替换片段。

    这里是关于片段https://guides.codepath.com/android/Creating-and-Using-Fragments的教程

    【讨论】:

    • 我开始使用片段有点晚,并且已经完成了大量的活动。我会在下一个应用程序中只使用一个活动并且只使用片段,但是对于这个,工作太接近尾声并且截止日期是两天,所以我现在无法真正修改所有内容..这就是为什么我正在寻找一种方法来清除这种奇怪的内存消耗。但是使用片段是一个非常好的解决方案。
    【解决方案3】:

    好的,好消息(有点)。问题不在我最初认为的地方。我将这个内存问题搁置了几个小时,并继续研究应用程序的最后一个功能。在测试我的新代码时,在获得 OOM 之前,我无法在活动之间导航超过 3 次。我就像“等一下,我之前可以切换几个小时而不会出错”。所以我用 Git 找到了第一个存在这个内存泄漏问题的提交。它首次出现时带有照片上传功能。所以,我的内存泄漏可能是因为一些未回收的位图。在 Stack 和 Internet 上的其他地方可以找到很多位图内存错误,我应该能够弄清楚。感谢所有回复的人!

    【讨论】:

      猜你喜欢
      • 2014-07-02
      • 1970-01-01
      • 2021-08-11
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多