Large heap with slow but infrequent garbage collection
var tmp = new System.Object[1024]; // make allocations in smaller blocks to avoid them to be treated in a special way,which is designed for large blocks for (int i = 0; i < 1024; i++) tmp[i] = new byte[1024]; // release reference tmp = null;
诀窍是在程序启动时预先分配一些内存块.
为什么这个招式有效?
这些块在预分配时是否为“注册”(或“绑定”),因此即使在完成Start()时tmp正在被释放,操作系统仍将这些块视为“注册“到应用程序?
由于块被“注册”到应用程序,所以应用程序的堆大小扩展到一定的大小,下次获取内存块时,操作系统只会从该应用程序堆中选择它.
我的解释是否正确?不管是或否,有人可以详细解释,谢谢.
解决方法
在Unity3D中,您具有由Mono处理并将被垃圾回收的对象以及由Unity处理的对象,这些对象不会被垃圾回收.字符串,整数等都由Mono自动清理,我们不用担心.纹理(2D)等不是,我们必须手动处理这些对象.
当进行内存请求时,首先发生的情况是内存管理器从操作系统扫描应用程序当前分配的内存足够大以存储要请求的数据.如果找到匹配,则使用该内存.如果未找到匹配项,则应用程序将从操作系统请求其他内存以存储数据.当这个数据不再耗尽时,它被垃圾回收,但应用程序仍然保留该内存.实质上,它在内存上设置一个标志,表示它是“可用”或可重新分配的.这样可以减少对操作系统的内存请求.
这是什么意思是两件事情?
1)您的应用程序的内存只会继续增长,并且不会将内存返回到操作系统.在移动设备上,这是很危险的,就像您使用太多内存,您的应用程序将被终止.
2)您的应用实际上可能被分配的方式比实际需要更多的内存.这是由于内存碎片.您的应用程序的内存池中可能有10MB的可用内存,但这些块的大小足够容纳您需要存储的数据.因此,应用程序可能会从OS请求更多的内存,因为没有可以使用的单个连续的可用内存.
因为您正在创建一个大对象,因此请求内存,当您将该对象设置为null并向应用程序不再需要内存的垃圾收集器发出信号时,更快将该保存的内存重新分配给其他对象,而不是从操作系统请求额外的内存.正是这个原因,为什么在理论上这个特定的方法是快速的,并且会导致更少的性能尖峰,因为垃圾收集器被调用的频率较低.特别是因为这是一个大的,连续的内存分配.