我正在为有限RAM的设备编写C#应用程序。 (iPhone / iPad上的单声道)
当我指定一个大字符串时:
string xml = "10 meg xml string from REST service";
然后清除它
xml = null;
GC是否尽快释放内存?有没有办法确保它被清理干净。 GC有一个收集功能,但这是立即执行的吗?
问题是我在循环中下载了很多大型xml文件,即使我将字符串设置为null,内存使用也在增长。
答案 0 :(得分:4)
一般情况下GC不会立即发生,因为垃圾收集相对昂贵。运行时通常会尝试在不忙于执行其他操作时执行此操作,但这显然并非总是可行。我曾经遇到过一个非确定性的内存不足错误,因为当我运行紧密的内存密集型循环时,它推迟了GC太长时间(有时)。课程:通常收集器知道它在做什么,你不需要调整它。但并非总是如此。
要强制收集,您需要两行:
GC.Collect();
GC.WaitForPendingFinalizers();
编辑:在我看到你关于你正在运行的内容的说明之前写了这个。这是基于桌面.NET机器编写的。它可能(也可能不)在mono / iPad上有所不同。
答案 1 :(得分:2)
首先,应避免一次将大字符串或大型数组保留在内存中,尤其是在手机等内存受限的设备上。例如,使用XmlTextReader来解析xml文件。如果从网络上获取它们,请将它们保存到磁盘等等。
接下来,关于垃圾收集的问题:当前的Mono GC对线程堆栈执行保守扫描,这意味着GC的某些指针可能仍然可见,即使对程序员它们已被清除(比如在你的例子中设置为null)。 要限制此行为的后果,您应该尝试在单独的堆栈帧中分配或以其他方式操作大数组和字符串。例如,而不是这样编码:
while (true) {
string s = get_big_string_from_network ();
do_something_with_string(s);
handle_ui ();
s = null;
}
执行以下操作:
void manipulate_big_string() {
string s = get_big_string_from_network ();
do_something_with_string(s);
}
...
while (true) {
manipulate_big_string ();
handle_ui ();
}
通常,将引用设置为null仅在应用于静态或实例字段时才具有预期效果,使用方法局部变量可能不足以隐藏GC中的引用。
答案 2 :(得分:2)
我认为如果你正在为iPhone开发,你就没有.net框架中的gargabe收集器。内存管理由操作系统构成,在本例中为iOS。
我认为您应该检查单声道文档,以便找到在这种情况下如何管理内存。 XCode实现和自动对象管理称为自动引用计数,并不像.net框架中的那个垃圾收集只是一个释放未使用对象的自动工具。
现在在使用大字符串时只考虑.net,你应该总是使用stringbuilder而不是字符串。
现在想在iOS中你不能将为iOs环境编写的应用程序与用于Windows的桌面应用程序进行比较(在PC中你有更多的资源)。 iOS不会让内存消耗大打折扣,如果应用程序执行此操作,操作系统将自动关闭它以保持系统运行。
答案 3 :(得分:1)
虽然我不是单声道专家,但要检查一些简单的事情。虽然您注意到您将变量设置为null,但实际上是否正在调用.Close()或.Dispose()方法,或者在使用块中包含相关变量的范围?
可能是一个问题,你正在等待终结器(即如果你有一个像文件句柄这样的无法保证的资源上的句柄),或者由于某种原因变量仍然停留在范围内。这会导致内存压力增加。
理想情况下,处理在具有显式清除变量范围的方法中结合使用块一次打开一个文件,从而确保即使抛出异常也会调用适当的终结符等。
希望有所帮助!