我正在优化我关于内存消耗的应用程序,并且发现GC(sgen)不时很懒,所以它不会清理到目前为止已经处理了很长时间的所有东西。我甚至不知道是否会收集这些内容,这对于所有指向本机资源(UIImage等)的指针尤其重要。
所以我开始在我的应用程序中的某些点手动调用GC,例如在弹出或关闭控制器时。
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
我知道这需要一些时间才能完成,但我还有其他的缺点需要考虑吗?
答案 0 :(得分:6)
是的,还有其他一些缺点。
即使您调用GC.Collect,也无法确保您认为已消失的对象实际上已消失。可能存在对托管代码或非托管代码无法看到的对象的引用。
就GC而言,像“UIImage”这样的对象只占用少量字节,你可能会加载几千个这些对象并占用兆字节的RAM,但据GC知道这只是一个几KB的数据。
这是因为GC不知道那些无辜的UIImage对象实际上指向了非托管空间中的一块巨大的内存块。
这也发生在.NET上。有一些宝贵的资源,一旦你停止使用它们就应该返回给所有者,而不是依靠GC来收集物体,因为GC真的不知道可爱的小物体有多重要。
这些资源通常是图像(它们占用大量RAM),网络连接(你有那些数量有限),数据库连接(有时你可能会按连接收费),文件(有限数量的句柄)和东西那样的。
那些实现IDisposable接口,你应该在完成后立即调用Dispose()。
UIImage就是其中之一。您需要主动调用这些对象的Dispose。
在Xamarin.iOS中说过,NSObject子类的所有东西都是IDisposable。这是我们采用强制放弃非托管资源所有权的模式,即使其中许多资源不是很昂贵(NSString,NSUrl等)。
最好的策略是运行探查器,识别你的胖,大物体,并确保你尽早处理它们。