首先看下Dictionary的源碼html
public void Add (TKey key, TValue value) { if (key == null) throw new ArgumentNullException ("key"); // get first item of linked list corresponding to given key int hashCode = hcp.GetHashCode (key) | HASH_FLAG; int index = (hashCode & int.MaxValue) % table.Length; int cur = table [index] - 1; // walk linked list until end is reached (throw an exception if a // existing slot is found having an equivalent key) while (cur != NO_SLOT) { // The ordering is important for compatibility with MS and strange // Object.Equals () implementations if (linkSlots [cur].HashCode == hashCode && hcp.Equals (keySlots [cur], key)) throw new ArgumentException ("An element with the same key already exists in the dictionary."); cur = linkSlots [cur].Next; } if (++count > threshold) { Resize (); index = (hashCode & int.MaxValue) % table.Length; } // find an empty slot cur = emptySlot; if (cur == NO_SLOT) cur = touchedSlots++; else emptySlot = linkSlots [cur].Next; // store the hash code of the added item, // prepend the added item to its linked list, // update the hash table linkSlots [cur].HashCode = hashCode; linkSlots [cur].Next = table [index] - 1; table [index] = cur + 1; // store item's data keySlots [cur] = key; valueSlots [cur] = value; generation++; }
int hashCode = hcp.GetHashCode (key) | HASH_FLAG;
hcpgit
[Serializable] sealed class DefaultComparer : EqualityComparer<T> { public override int GetHashCode (T obj) { if (obj == null) return 0; return obj.GetHashCode (); } public override bool Equals (T x, T y) { if (x == null) return y == null; return x.Equals (y); } }
其實就是走到obj.GetHashCode,若是obj.GetHashCode沒有覆蓋的話,那就會走到ValueType的GetHashCodegithub
public override int GetHashCode () { object[] fields; int result = InternalGetHashCode (this, out fields); if (fields != null) for (int i = 0; i < fields.Length; ++i) if (fields [i] != null) result ^= fields [i].GetHashCode (); return result; }
注意看ide
[MethodImplAttribute (MethodImplOptions.InternalCall)] internal extern static int InternalGetHashCode (object o, out object[] fields);
int result = InternalGetHashCode (this, out fields);
會把this轉成object類型,第1次boxing,並且會把每一個字段都轉成object,放入fields裏,因此會有屢次gc alloc
這個是不重載GetHashCode致使的gc alloc。
下一個是
if (linkSlots [cur].HashCode == hashCode && hcp.Equals (keySlots [cur], key))
hcp.Equalsui
若是T沒有實現IEquatable,就會走到DefaultCOmparer,而後會走到this
這個Equals會調用ValueType.Equalsspa
internal static bool DefaultEquals (object o1, object o2) { object[] fields; if (o2 == null) return false; bool res = InternalEquals (o1, o2, out fields); if (fields == null) return res; for (int i = 0; i < fields.Length; i += 2) { object meVal = fields [i]; object youVal = fields [i + 1]; if (meVal == null) { if (youVal == null) continue; return false; } if (!meVal.Equals (youVal)) return false; } return true; } // <summary> // True if this instance and o represent the same type // and have the same value. // </summary> public override bool Equals (object obj) { return DefaultEquals (this, obj); }
這個裏面會把x,y都轉成object.因此會有2次boxing3d
至此全部的boxing都清楚了,工程例子在code
https://github.com/yingsz/DictionaryAllochtm
消除boxing參考
http://www.bkjia.com/Asp_Netjc/1314145.html