在C#中如果我使用以下代码
Dictionary<int,object> dictionary = new Dictionary<int, object>();
dictionary.Add(1,null);
dictionary.Add(2,new object());
dictionary[2] = null;
分配了多少内存? 字典中的每个对象引用(字典[1],字典[2])是否在堆上获取指针大小(32或64位)?换句话说,当我执行dictionary.Add(1,null)时,CLR会自动在堆上创建2个分配,一个用于int,一个用于空指针吗?
答案 0 :(得分:16)
空指针不会分配任何额外的内存来存储堆上的任何内容(因为没有任何东西需要存储)。但是,您的字典必须存储空指针本身,它占用的空间与任何其他指针一样多。
每个add调用是否导致新的分配(存储指针)取决于Dictionary实现。通常,它有一个内部数组,可以根据需要重新调整大小。
在您的示例中,我假设在创建字典时已经为少数元素分配了足够的空间。所以add(1,null)不会再分配任何空间。
更新:未指定default initial capacity for Dictionary。在.NET 4.0中,它实际上从0开始,因此第一个添加将创建存储阵列。
答案 1 :(得分:2)
本身的空指针将占用4或8个字节,具体取决于它是以32位还是64位运行,如您所推测的那样。
在给定的集合中可以有更多。 Dictionary<TKey, TValue>
的实现使用Entry<TKey, TValue>
结构数组,其中包含两个int
以及键和值,以及用于索引到该数组的整数数组。因此,即使没有“增长空间”(并且通常存在),每个条目都需要20字节或24字节的内存(而不仅仅是密钥和值的大小所需的8或12),除了开销之外字典本身(包括每个数组的开销)。
其他实现和其他集合将有其他开销。他们甚至可能不会为{null}条目存储null
。 null
可以是指示未写入值的有用方法,在这种情况下,特殊值将指示null
的实际值(在无锁字典实现中特别有用,它可以是有用的区分不仅是未设置值和设置值,而是区分未设置,设置和部分设置值。
你真正可以说的是,添加值null
A)的设置会占用一些内存而B)不会占用内存,而对象本身会占用非空值。即使B)也没有真正成立,因为如果该对象也存储在其他地方,那么除了引用本身之外,在其他地方有另一个引用没有额外的内存成本,这使得它的实际成本与存储{{ 1}}。
答案 2 :(得分:0)
我想是的,因为null是一个参考。它指向无处,但您可以每次使用真实对象引用替换它。
所以我想至少分配了2x64bit,也许Dictionary需要额外的空间。