我的 iPad 应用程序是在 MonoTouch 中开发的,因为我想避免所有的内存管理地狱,但似乎并非如此。在模拟器上一切正常,但是当我在设备上测试我的应用程序时,我惊恐地发现它在一些内存警告后很快被操作系统杀死。我的应用程序是一个简单的图像浏览器,它加载一些 PNG 图像并使用 UIScrollView 中的一些 UIView 显示它们,在触摸时加载下一个或上一个。在模拟器上它工作正常。但是在设备上加载和卸载大约 6-11 个图像后,它开始收到内存警告,然后突然进程被终止。我检查了所有实例化周期,并且在加载新图像之前正确删除了所有引用。
所以我启动了 Instruments 并开始分析我的应用在 iPad 上的内存分配。在那里我发现 Live 字节只有大约 5-9 MB,这正是我的预期,但由于某种奇怪的原因,几乎没有收集到死内存分配,因为在分配了大约 50 MB(小于 5-9 MB它是 Live Bytes)它被杀死了!这是我的应用程序的仪器分析会话的屏幕截图:
这是heapshots序列:
也有一些小的泄漏,但我认为它们还不足以成为罪魁祸首。它们都是来自 strdup 的 48 字节泄漏,这是在 iOS 5.1 中发布 UIScrollView 时的一个已知问题:
即使看起来一切正常,分配的 Live Bytes 仍为 5 MB,但我的应用程序的实际内存呈指数增长,然后在 iPad 上达到 50MB,在 iPhone4S 上达到 314 MB,如 Memory Monitor 报告的那样:
有人可以告诉我是否有方法或实用程序来发现问题所在和位置?这是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;
}
是否有一种方法可以捕获未正确处理的对象?Instruments 报告活动字节很低,泄漏几乎为零,那么为什么不处理死对象呢?即使我的应用程序几分钟内什么都没发生,GC 似乎也没有完成他的工作,即使我在我的代码中明确地称之为它。我什至尝试了新的实验性垃圾收集器,但让我的应用程序被杀死的情况更糟、更快。
我在 Xamarin 网站上找不到任何用于解决内存警告或跟踪错误分配的指南或分步指南。
非常感谢任何帮助或建议,谢谢!
更新:我降低了一些图像和 uiview 的大小和分辨率,Live Bytes 现在从 9 MB 降至 5 MB,但无论如何,在一些内存警告之后,该应用程序仍然被终止。
更新 2:正如 Javier 所建议的,我已经删除了后台任务并直接进行了调用,并且内存泄漏消失了!似乎 MonoTouch 垃圾收集器有一个错误,当 UIImages 分配和处理在不同的线程中时,它无法收集内存。但是现在当我滚动时,我的应用程序非常没有响应,所以我需要找到一个解决方案来在不同的线程中执行它!但是怎么做?