空指针使用多少内存?

16

如果我在C#中使用以下代码:

Dictionary<int,object> dictionary = new Dictionary<int, object>();
dictionary.Add(1,null);
dictionary.Add(2,new object());
dictionary[2] = null;

有多少内存被分配? 字典中的每个对象引用(dictionary [1],dictionary [2])在堆上是否占用指针大小(32位或64位)?换句话说,当我执行dictionary.Add(1,null)时,CLR是否自动在堆上创建了两个分配,一个用于int,另一个用于空指针?

3个回答

17

空指针不会分配任何额外的内存来存储堆上的任何内容(因为没有要存储的内容)。但是,您的字典必须存储空指针本身,这需要与任何其他指针一样多的空间。

每个add调用是否导致新的分配(以存储指针)取决于Dictionary实现。通常,它有一个内部数组,根据需要进行重新调整大小。

在您的示例中,我会假设在创建字典时已经分配了足够的空间以容纳一些元素。因此,add(1, null)将不会再分配任何空间。

更新:Dictionary的默认初始容量未指定。在.NET 4.0中,它实际上从0开始,因此第一个add将创建存储数组。


非常好的答案,谢谢!我正在学习链表--系统如何处理链表创建无限数量的空指针这一事实?显然它们并不都被使用,但是具有数据和节点指针的节点结构体的创建会递归地创建指针节点。这在内存中是如何处理的?每个空指针都有一个内存地址吗?计算机是否根据需要动态分配该内存? - Federico

3

一个空指针本身将占用4或8个字节,具体取决于它是在32位还是64位下运行,正如您所想象的那样。

在给定的集合中可能会有更多。 Dictionary<TKey, TValue> 的实现同时使用了一个包含两个int(以及键和值)的Entry<TKey, TValue>结构的数组,以及一个用于索引该数组的整数数组。因此,即使没有“增长空间”(通常都有),每个条目也需要20字节或24字节的内存(而不仅仅是键和值大小所涉及的8或12字节),加上字典本身的开销(包括每个数组的开销)。

其他实现和其他集合将具有其他开销。它们甚至可能不为null条目存储null。在这种情况下,null可以是一种有用的表示尚未编写的值的方式,在这种情况下,特殊值将指示实际的null值(特别是在无锁字典实现中非常有用,因为它可以区分未设置和已设置的值,但不能区分未设置、已设置和部分设置的值)。

你真正能说的就是,添加null值A)占用一些内存,B)不占用非空值本身将占用的内存。即使B)也不完全成立,因为如果该对象也存储在其他位置,则除了引用本身之外,再有另一个引用没有额外的内存成本,这使得它的真实成本与存储null相同。


0

我认为是的,因为null是一个引用。它指向无处,但你可以每次用一个真正的对象引用替换它。

所以我猜至少分配了2x64位,也许字典需要额外的空间。


我同意你的答案,但是我有一个关于这个问题的疑问。指针是int32或int64变量,所以即使你将它们设置为null,我们在内存中仍然有int32对象作为指针变量,对吗? - Dr TJ
@ Dr TJ:指针实际上不是int32或int64对象,但它们具有相同的大小。例如,Double与int64具有相同的大小,但是它们是不同的类型。空指针由32或64个零位表示,这些位显然必须存储在某个地方。 - MSalters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接