C# 为什么这种内存管理技巧有效?

C# 为什么这种内存管理技巧有效?,c#,memory-management,unity3d,C#,Memory Management,Unity3d,参考并转到第节 大堆,垃圾收集速度慢但不频繁 var tmp=newsystem.Object[1024]; //在较小的块中进行分配,以避免它们被特殊方式处理,这是为较大的块设计的 对于(int i=0;i

参考并转到第节

大堆,垃圾收集速度慢但不频繁

var tmp=newsystem.Object[1024];
//在较小的块中进行分配,以避免它们被特殊方式处理,这是为较大的块设计的
对于(int i=0;i<1024;i++)
tmp[i]=新字节[1024];
//发布参考
tmp=null;
诀窍是在程序开始时预先分配一些内存块

为什么这个把戏有效

这些区块在预分配时是否某种程度上被“注册”(或“绑定”)到应用程序,因此即使
tmp
Start()
完成时被释放,操作系统仍然将这些区块视为“注册”到应用程序? 由于块被“注册”到应用程序,因此应用程序的堆大小被扩展到一定的大小,下次它获取内存块时,操作系统将从该应用程序的堆中拾取它

我的解释正确吗?不管是不是,请有人详细解释一下,谢谢

为什么这个把戏有效


这个技巧之所以有效,是因为应用程序不会将内存返回到操作系统,除非操作系统内存管理器很低,并显式地请求它们这样做,然后它们将尽可能地释放内存。有一种假设,即一旦分配了内存,就会再次需要它。如果已经分配了,就没有理由将其返回操作系统,除非它真的需要使用它。

这不是一个真正的技巧。这是Unity3D部分处理内存的方式

在Unity3D中,有由Mono处理并将被垃圾收集的对象,也有由Unity处理但不会被垃圾收集的对象。字符串、int等由Mono自动清理,我们不必担心这一点。纹理(2D)等不是,我们必须手动处理这些对象

当发出内存请求时,首先发生的事情是内存管理器从操作系统扫描应用程序当前分配的内存,以查找足够大的块来存储所请求的数据。如果找到匹配项,则使用该内存。如果未找到匹配项,则应用程序将从操作系统请求额外内存以存储数据。当这些数据不再被使用时,它将被垃圾收集,但应用程序仍保留该内存。本质上,它在内存上设置了一个标志,表示它“可用”或可重新分配。这通过从不返回操作系统来减少对内存的请求

这意味着两件事

1) 应用程序的内存只会继续增长,不会将内存返回操作系统。在移动设备上,这是危险的,因为如果您使用太多内存,您的应用程序将被终止

2) 您的应用程序实际分配的内存可能比实际需要的内存多得多。这是由于内存碎片造成的。应用程序的内存池中可能有10MB的可用内存,但这些内存块中没有一块足够大,可以容纳需要存储的数据。因此,应用程序可能会从操作系统请求更多内存,因为没有可用的连续内存


因为您正在创建一个大对象,因此请求内存,当您将该对象设置为null并向垃圾收集器发出应用程序不再需要内存的信号时,将保留的内存重新分配给其他对象比从操作系统请求额外内存更快。这就是为什么在理论上,这个特定的方法速度很快,并且由于垃圾收集器调用的频率较低,因此会导致性能峰值较低的原因。特别是因为这是一个大的连续内存分配。

@downvoter-想了解一下您看到的错误吗?
    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;