MonoTouch的:应用程序处死低MEM,为什么呢? 直播字节分配5 MB顶部(MonoTou

2019-06-24 01:45发布

我的iPad应用程序在MonoTouch的发展,因为我想避免所有的内存管理的地狱,但它似乎并不如此。 在模拟器上一切正常,但是当我测试我的应用程序在设备上我惊恐地发现,它是由OS一些内存警告后迅速死亡。 我的应用程序是一个简单的图像浏览器,它加载某些PNG图像,并显示他们使用的UIScrollView里面的一些UIViews,得到一个触摸时加载下一个或上。 在模拟器上正常工作。 但在设备上加载和卸载约6-11图像后,开始得到内存警告,然后突然进程被杀死。 我检查了我所有的实例化周期,我加载新的图像之前正确删除所有引用。

于是我开始仪器,开始剖析我的应用程序在iPad上的内存分配。 在那里,我发现现场字节只有大约5-9 MB,正是我的预期,但由于一些奇怪的原因,死者内存分配几乎没有在所有收集到的,因为分配约50 MB(小于5-9 MB的后它是活字节)它被杀死! 这里是仪器剖析我的应用程序会话的截图:

这里是heapshots序列:

也有一些小的泄漏,但我认为他们是没有大到足以成为罪魁祸首。 他们都是48所字节泄漏的strdup从在的iOS 5.1发布时的UIScrollView一个已知的问题:

即使考虑到这似乎确定和分配的现场字节仍处于5 MB的一切,我的应用程序的实际内存被杀害高达50MB的iPad之前呈指数级增长,并达到对iPhone4S的314 MB,所报告的内存监视器:

是否有人可以告诉我,如果有一种方法或工具来发现什么,哪里出了问题? 它是MonoTouch的垃圾收集器的错误吗? 还是有一些对象,我不正确处置? 而我怎么能找到那些与探查? 我检查我的代码了两天,但一切似乎是正确的。

这里是我的装载/实例化/配置周期代码:

    void StartImageLoadingThread()
{
    tokenSource = new CancellationTokenSource ();
    token = tokenSource.Token;
    Task task1 = new Task( () => PerformLoadImageTask(token),token);
    task1.Start();
}


void PerformLoadImageTask(CancellationToken token)
{
        if (token.IsCancellationRequested)
                {
                     Console.WriteLine("Task {0}: Cancelling", Task.CurrentId);
                return;
                }

            current_uiimage_A = UIImage.FromFileUncached(file_name);
            page_A_image_view.Image = current_uiimage_A;


} 


void UnloadImageAFromMemory()
{
      page_A_image_view.Image = null;
      current_uiimage_A.Dispose();
      current_uiimage_A = null;
}   

有没有赶上未正确配置的对象的方法? 仪器报道说,现场字节低,泄漏几乎为零,那么为什么死的对象不处置? 即使没有在我的应用程序用于分钟发生,GC似乎并没有使他的工作,即使我明确地把它在我的代码。 我甚至尝试了新的实验垃圾收集器,但它更是雪上加霜,更快地让我的应用程序被杀害。

我找不到任何指导或一步一步引导Xamarin网站上的故障排除内存警告或跟踪不好分配。

任何帮助或建议非常赞赏,谢谢!

更新:我已经减小了尺寸和一些图像和uiviews的分辨率,现在直播字节被丢弃,从9 MB到5 MB顶部,但一些内存警告后,应用仍在杀害不管。

更新2:正如哈维尔建议我已经删除了后台任务,并直接进行调用和内存泄漏消失了! 看来,MonoTouch的垃圾收集器有一个bug,无法收集内存时UIImages分配和布置在不同的线程。 但现在我的应用程序是,当我滚动不亦乐乎反应迟钝,所以我需要找到一个解决方案,以做到在不同的线程! 怎么会呢?

Answer 1:

我有问题UIImage.FromFile 。 我的应用程序加载大量使用任务PNG图像,并显示在主线程它。

我加了一个GC.Collect后台任务,但它并没有固定的问题。 我不得不删除后台任务,做所有的东西在主线程和调用GC.Collect 。 看来,Image.Dispose不释放图像存储器:(

但是,当你有另一个任务是不行的,所以我不得不删除它:(

是的,它是不工作....



Answer 2:

您需要使用NSAutoreleasePools图像周围创建代码,像这样:

void PerformLoadImageTask(CancellationToken token)
{
    if (token.IsCancellationRequested)
    {
         Console.WriteLine("Task {0}: Cancelling", Task.CurrentId);
         return;
    }

    using (var pool = new NSAutoreleasePool ()) {
        current_uiimage_A = UIImage.FromFileUncached(file_name);
        page_A_image_view.Image = current_uiimage_A;
    }
}

对于创建对象的一些API的对象将被添加到自动释放池,而不是释放,直到池排出。 MonoTouch中自动创建所有用户线程(包括线程池,第三方物流和正常的System.Threading线程)自动释放池,但这些池不被排干,直到线程退出(你不能在线程池和TPL线程的情况下控制)。 因此,解决方案是使用一个NSAutoreleasePool围绕关键代码(设置当池将自动排水)。



Answer 3:

这是对我有意思,我刚开始看内存管理,我甚至不知道这是必须空和对象,并调用处理,因为范围规则应该为你做的工作? 但是它会帮助垃圾收集器做尽快。

明确要求垃圾收集器运行是一个请求,并不能保证。

猜想 ,在UI线程上创建的对象是在UI线程的一个外被引用,并会在那里寻找,但我不知道。

我期待着在此看到的更新,因为我敢肯定,我会遇到类似的问题!

祝你好运,罗布



文章来源: MonoTouch: App killed for low mem, Why? Live bytes allocation 5 MB top