建立簡單類別 Foo,於 GetHashCode() 呼叫前後檢查物件頭部:
Foo f = new Foo();
Console.WriteLine(f.GetHashCode());
Console.ReadLine();
0x000000000x0F78734A (十進位 259,815,242)58225482 (二進位 00000011 01111000 01110011 01001010)發現:SyncBlockIndex 低 26 位完全等於回傳的 HashCode,高 6 位為旗標。
public virtual int GetHashCode() => InternalGetHashCode(this);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int InternalGetHashCode(object obj);
INT32 ObjectNative::GetHashCodeEx(Object* objRef)
{
while (true)
{
DWORD bits = objRef->GetHeader()->GetBits(); // 取得 SyncBlockIndex
if (bits & BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX)
{
if (bits & BIT_SBLK_IS_HASHCODE)
return bits & MASK_HASHCODE; // 低 26 位即 HashCode
else
{
// 已有 SyncBlock,HashCode 可能在 SyncBlock.m_dwHashCode
SyncBlock* psb = objRef->GetSyncBlock();
DWORD hashCode = psb->GetHashCode();
if (hashCode != 0) return hashCode;
hashCode = Object::ComputeHashCode();
return psb->SetHashCode(hashCode);
}
}
else
{
// 尚無同步區塊也無 HashCode
if ((bits & (SBLK_MASK_LOCK_THREADID | ...)) != 0)
{
objRef->GetSyncBlock(); // 強制分配 SyncBlock,下一輪處理
}
else
{
DWORD hashCode = Object::ComputeHashCode();
DWORD newBits = bits | BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_IS_HASHCODE | hashCode;
if (objRef->GetHeader()->SetBits(newBits, bits) == bits)
return hashCode;
// 競爭失敗重試
}
}
}
}
BIT_SBLK_IS_HASHCODE | BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX。BIT_SBLK_IS_HASHCODE → 直接回傳 bits & MASK_HASHCODE (低 26 位)。m_dwHashCode。MASK_HASHCODE = (1<<26)-1 精準擷取低 26 位,零成本取值。SetBits) 確保多執行緒安全初始化。