簡體   English   中英

IdentityHashMap.hash() 中這段代碼的用途是什么?

[英]What is the purpose of this code in IdentityHashMap.hash()?

/**
 * Returns index for Object x.
 */
private static int hash(Object x, int length) {
    int h = System.identityHashCode(x);
    // Multiply by -127, and left-shift to use least bit as part of hash
    return ((h << 1) - (h << 8)) & (length - 1);
}

來自: jdk/IdentityHashMap.java 在 jdk8-b120 · openjdk/jdk · GitHub

理論上System.identityHashCode()返回的 hash 值已經是均勻分布的了,那為什么還要多一個移位運算而不是直接length - 1的 AND 運算呢?

該實現似乎保證最低位為 0 以確保計算結果為偶數,因為該實現要求所有鍵都在偶數索引上,所有值都在奇數索引上。

h << 8似乎混合了低位和高位來處理當 System.identityHashCode() 被實現為 memory 地址或遞增值時的情況,目前尚不清楚為什么這里只移動 8 位而不是HashMap.hash()也移動 16 位。

代碼中的注釋說:

hash table, as described for example in texts by Sedgewick and Knuth. The array alternates holding keys and values." “實施說明:這是一個簡單的hash 表,如 Sedgewick 和 Knuth 的文本中的示例所述。數組交替保存鍵和值。”

事實上, hash方法返回一個值,該值用作數組的直接索引。 例如:

public V get(Object key) {
    Object k = maskNull(key);
    Object[] tab = table;
    int len = tab.length;
    int i = hash(k, len);
    while (true) {
        Object item = tab[i];
        if (item == k)
            return (V) tab[i + 1];
        if (item == null)
            return null;
        i = nextKeyIndex(i, len);
    }
}

這意味着hash需要返回偶數。 hash中的計算確保索引是均勻的,而不會丟棄System.identityHashCode(x)值的底部位。

為什么不扔掉最底層的部分呢?

好吧,答案在於System.identityHashCode的實現方式。 實際上,有多種算法可以生成 hash,所使用的算法(在運行時)取決於一個模糊的 JVM 命令行選項。

  • 一些算法(名義上)均勻分布在int的范圍內。 對於那些人,丟棄底部位就可以了。

  • 其他算法不是這樣的。 其中一種算法使用簡單的全局計數器。 另一個使用對象的 memory 地址,刪除了低 3 位。 如果選擇這些算法,丟棄 LSB 會增加IdentityHashMap中發生 hash 次沖突的概率。

有關IdentityHashcode算法及其選擇方式的更多信息,請參見https://shipilev.net/jvm/anatomy-quarks/26-identity-hash-code/ 請注意,JVM 行為的這一方面是未指定的,並且可能是特定於版本的。

我對這里發生的事情的預感是它旨在解決兩個問題。

首先,這個 function 產生的槽索引必須是偶數。 (該實現將鍵存儲在偶數表槽中,將值存儲在奇數表槽中。)這意味着無論返回什么索引,其最后一位都必須為零。

其次,使用的標識 hash 代碼(可能)基於 memory 地址,memory 地址的低位比高位“更隨機”。 例如,如果我們分配一個對象列表,並且分配器將它們全部連續放置在 memory 中,那么它們的地址將具有相同的高位但低位不同。 (或者也許只有一個全局對象計數器在創建 object 時遞增。在這種情況下,object 哈希的低位將同樣比高位具有更廣泛的分散。)

為了確保表格中的內容分散,我們因此希望將 hash 代碼的低位與 hash 代碼的“高”位“混合”。 減去h << 8的效果是將標識 hash 代碼的低位向上移動,翻轉它們,然后將它們添加回 hash 代碼,在加法運算時引起一堆“漣漪”。 我認為(?)這是一種有效的方法,可以將更高熵的低位注入高位,一旦表開始變得越來越大,就可以在槽陣列上提供更均勻的 hash。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM