首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

同步區塊索引深度解析(中):GetHashCode 如何借用 SyncBlockIndex 儲存雜湊值

     編輯:關於.NET

Visual Studio + SOS 實驗觀察

建立簡單類別 Foo,於 GetHashCode() 呼叫前後檢查物件頭部:

Foo f = new Foo();
Console.WriteLine(f.GetHashCode());
Console.ReadLine();
  • 呼叫前:SyncBlockIndex = 0x00000000
  • 呼叫後:SyncBlockIndex = 0x0F78734A (十進位 259,815,242)
  • GetHashCode() 回傳:58225482 (二進位 00000011 01111000 01110011 01001010)

發現:SyncBlockIndex 低 26 位完全等於回傳的 HashCode,高 6 位為旗標。

Rotor 原始碼追蹤

Managed 入口

public virtual int GetHashCode() => InternalGetHashCode(this);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int InternalGetHashCode(object obj);

Native 實作 (ecall.cpp → ObjectNative::GetHashCodeEx)

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;
                // 競爭失敗重試
            }
        }
    }
}

核心邏輯總結

  1. 首次呼叫:物件頭無旗標 → 計算 HashCode → 寫入低 26 位,置 BIT_SBLK_IS_HASHCODE | BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX。
  2. 再次呼叫:偵測到 BIT_SBLK_IS_HASHCODE → 直接回傳 bits & MASK_HASHCODE (低 26 位)。
  3. 已轉為 Lock:旗標相同但低 26 位已是索引 → 取得 SyncBlock → 讀取/寫入 m_dwHashCode。

設計亮點

  • 同一 32 位欄位,透過高 6 位旗標動態切換「儲存 HashCode」與「指向 SyncBlock」兩種模式。
  • MASK_HASHCODE = (1<<26)-1 精準擷取低 26 位,零成本取值。
  • 無鎖 CAS (SetBits) 確保多執行緒安全初始化。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved