Re: [問題] HashCode 與 記憶體位置的關聯

看板java作者 (批踢踢世界)時間10年前 (2015/05/25 17:14), 10年前編輯推噓0(0038)
留言38則, 3人參與, 最新討論串5/5 (看更多)
我只討論觀念。 ※ 引述《Killercat (殺人貓™)》之銘言: : ※ 引述《noapaov (單身漢)》之銘言: : : 最近看了一下書籍, 不太清楚理解是否有錯, 想請教一下各位 : : Object 類別所提供的 hashCode() method, 主要是返回物件的記憶體位置 : : 經過運算後的整數, 所以與記憶體有密切關係 : : 所以每個物件的HashCode()理論上應該都不一樣, 但是有些子類別繼承後會 : : 進行equals和HashCode的覆寫,例如String、Array等, 所以就有可能造成 : : : 如果兩個物件使用equals(Object) 測試結果為不相等, : : 則這兩個物件呼叫 hashCode 時,可以獲得不同的整數結果("可以相同,也可以不同") : : 所以總結是如果繼承Object類的子類別, 沒有對equals hashCode進行改寫, : : 那麼這些物件產生的HashCode應該都不一樣, 但如果重寫就有可能造成HashCode相等, 但不一定是參考相同的記憶體位置情況 : : 不知道原理是否是這樣 : 回文一下好了,我簡單說一下 : 1. hashCode()不見得跟記憶體位置有關,有興趣翻一下OpenJDK的String.hashCode() : 他的實作方式保證你看了會笑出來 : http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/ : classes/java/lang/String.java 覆寫方法。 : 縮 : http://tinyurl.com/mqguft4 : 2. 追下去原始碼的話你會發現 Object的hashCode是native : 但是你只要對現代Java的GC有一點認識的話,就知道GC是會搬動記憶體的 : 從Java6引入Hotspot GC以降,整個heap被分為young/old/permgen : http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/ 這是對的,有手動去調整或看過eclipse.ini就可以知道。 : 也就是說,你一個object的物件在記憶體裡面的位置根本是會跑來跑去的 : 他的hash會因此變來變去嗎?不會。 這個部分問題會變成你覺得物件的hashCode會永遠不變嗎? 我的主張是會變的。 : 那你覺得hashCode跟記憶體有沒有關係呢? : 目前來講「應該」是沒有,不然按這種搬法,要是有第二個object出現在heap同位置 : 那不就死翹翹了? 問題變成當第二個object出現的時候,第一個object的位置在那裏呢? 如果位置相同-->以現今的計算機架構有這種可能嗎?我主張沒有。 如果位置不同的話-->那hashCode會一樣嗎? 我主張不會。 更精確地我的本意為要以hashCode當作identifier時,就不應該讓他會。 讓他會一定是有特殊意義或特殊用途"故意"讓他一樣。 或是存在一種可能是覆寫這個hashCode()內容寫得很爛,容易產生一樣的結果。 : 我提供一下OpenJDK hashCode()的native C code給你參考一下 : 不同JVM有不同實作,不過我想再有implement Hotspot的JVM下 : 我想應該僅僅只是一個序列號而已 : http://tinyurl.com/mhhrehs (他實作請搜尋get_next_hash,可以對照.h去對簽名) : 在OpenJDK的VM實作,我們可以清楚地看到他其實只是一個遞增序列 : ok...這看不懂沒關係 : 總之,雖然我沒有Oracle JVM的原始碼,但是我想....那本書應該是錯的 : 這東西跟記憶體位置毫無關係 : 其實有興趣可以去翻一下 以不同JVM會有不同實作的情況下, 你的回答是"hashCode()不見得跟記憶體位置有關" 不見得類似於不一定,就變成Y and N,可Y可N,真的難以討論。 爭議點會是所謂的internal address一詞的解釋是? 沒有討論出結果,而且還會被反問為什麼要知道。 http://stackoverflow.com/questions/16105420/ java-object-hashcode-address-or-random 提供google關鍵字 java object.hashcode memory address java object hashcode changes java object hashcode implementation 眾多討論指向stackoverflow.com, 是個好網站。 但如果看完討論追一下回應(不只是回覆,還要看回覆的回覆,小字的那種) 還真的頗好笑的。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.248.170.63 ※ 文章網址: https://www.ptt.cc/bbs/java/M.1432545279.A.9C1.html

05/25 17:58, , 1F
OpenJDK原始碼來講不會變,spec的話要找找
05/25 17:58, 1F

05/25 17:59, , 2F
另外hashCode會變動的話會有很奇怪的事情發生
05/25 17:59, 2F

05/25 17:59, , 3F
你會在thread裡面赫然發現自己沒辦法等於自己...
05/25 17:59, 3F

05/25 17:59, , 4F
因為你存下來的hashCode已經不能作準了
05/25 17:59, 4F
嗯。 "你會在thread裡面赫然發現自己沒辦法等於自己..." 這句是我沒看懂的地方,概念上模糊,你可以選擇是否進一步解釋。但我不會追問。 我以 https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html 其中public int hashCode() 有一句寫著 Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application. 我不翻譯整段因為不想強調英文。 只講need not remain consistent為"不需要維持一致" ※ 編輯: pttworld (111.248.170.63), 05/25/2015 18:11:11

05/25 18:10, , 5F
上面有板友提到一個更好的例子 : HashMap
05/25 18:10, 5F

05/25 18:11, , 6F
HashTable...er..一樣啦
05/25 18:11, 6F

05/25 18:12, , 7F
通常來說啦,會不會變來變去是討論你引的這段話的第一句
05/25 18:12, 7F

05/25 18:12, , 8F
在單一JVM生命週期內,要扯到不同次JVM生命週期的話只能說
05/25 18:12, 8F

05/25 18:12, , 9F
你高興就好,但是請註明。
05/25 18:12, 9F

05/25 18:13, , 10F
他的意思是說,在同一個jvm週期必須相等,而不同jvm
05/25 18:13, 10F

05/25 18:13, , 11F
再來Killercat原文舉的例子是用單一週期內GC的行為
05/25 18:13, 11F

05/25 18:13, , 12F
週期不需要相等。我想我們討論應該都是以同JVM週期為
05/25 18:13, 12F

05/25 18:13, , 13F
前提,對吧?
05/25 18:13, 13F
好的, 所以同JVM週期hashCode值相同且記憶體搬來搬去 = hashCode()和記憶體位置毫無關係? 這樣?

05/25 18:15, , 14F
另外threading的問題比較複雜難解釋,不如hash table
05/25 18:15, 14F

05/25 18:15, , 15F
那麼簡單易懂,我會說是我例子舉得比較難懂 XD
05/25 18:15, 15F

05/25 18:15, , 16F
我只是想說,Thread實作通常會把自己Thread ID記下來
05/25 18:15, 16F

05/25 18:16, , 17F
這個thread ID通常就是hashCode,要是會變來變去的話
05/25 18:16, 17F

05/25 18:16, , 18F
那你會連出去的Thread在哪都找不到
05/25 18:16, 18F

05/25 18:17, , 19F
這例子真的舉得有夠爛,所以還是Chikei的例子比較好
05/25 18:17, 19F
http://stackoverflow.com/questions/13860194/ what-is-an-internal-address-in-java hotspot/src/share/vm/runtime/synchronizer.hpp http://stackoverflow.com/questions/557574/ what-is-native-implementation-in-java/565416 ※ 編輯: pttworld (111.248.170.63), 05/25/2015 19:27:48

05/25 19:32, , 20F
目前沒開compiler下 我無法得知get_next_hash()裡面
05/25 19:32, 20F

05/25 19:32, , 21F
hashCode到底是什麼(看起來比較像Type)
05/25 19:32, 21F

05/25 19:33, , 22F
但是扣掉純粹拿ptr那個以及拿ptr併一個random計算以外
05/25 19:33, 22F

05/25 19:33, , 23F
其他的case看起來都不像有參考到obj的位置
05/25 19:33, 23F

05/25 19:34, , 24F
另外說真的internal address就看spec有沒有這個literal
05/25 19:34, 24F

05/25 19:34, , 25F
的定義就一翻兩瞪眼了... 有空再查查看
05/25 19:34, 25F

05/25 19:35, , 26F
另外 obj會游移這個是沒問題的 游移hashCode不會跟著
05/25 19:35, 26F

05/25 19:35, , 27F
變我想也是確定的(這個原始碼還挺清楚的) 所以這兩點
05/25 19:35, 27F

05/25 19:36, , 28F
姑且先當已經確定的共識吧
05/25 19:36, 28F

05/25 19:37, , 29F
不過我前一篇有非常明確的指名為什麼我不認為他跟記憶
05/25 19:37, 29F

05/25 19:37, , 30F
有關,因為他會動,所以要是新的object在已經被移走的
05/25 19:37, 30F

05/25 19:38, , 31F
舊object上產生呢?src裡面有一個case是說他是拿記憶體
05/25 19:38, 31F

05/25 19:38, , 32F
位置在對一個亂數mask作bitwise計算,這種前提下我不覺
05/25 19:38, 32F

05/25 19:38, , 33F
的這叫做「跟記憶體位置有關」
05/25 19:38, 33F
if (hashCode == 1) { // This variation has the property of being stable (idempotent) // between STW operations. This can be useful in some of the 1-0 // synchronization schemes. intptr_t addrBits = intptr_t(obj) >> 3 ; value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ; } else if (hashCode == 2) { value = 1 ; // for sensitivity testing } else if (hashCode == 3) { value = ++GVars.hcSequence ; } else if (hashCode == 4) { value = intptr_t(obj) ; } 大概就1和4吧,intptr_t有疑問。 只就字義上斷章取義只看ptr想成是指標好了, 那又想成c語言好了, 對於一個ptr隨便亂加好了, 到底加的這個計算是在加什麼的問題。 就當我亂想好了,反正我決定我該停在這裡就是了。 ※ 編輯: pttworld (111.248.170.63), 05/25/2015 19:45:34

05/25 20:59, , 34F
1就是我說的「我不認為這稱為記憶體位置」
05/25 20:59, 34F
3大概也不是

05/26 08:38, , 35F
3是明顯的serial sequence啊 XD
05/26 08:38, 35F
好。 ※ 編輯: pttworld (111.248.172.93), 05/26/2015 08:39:58

05/26 15:52, , 36F
jvm當初的目的就是希望寫程式可以不用管記憶體
05/26 15:52, 36F

05/26 15:53, , 37F
寫程式的時候,"不用先要塊記憶體來使用" "不用知道位置"
05/26 15:53, 37F

05/26 15:55, , 38F
希望只要專注在程式本身,而記憶體這種事就交給VM就好
05/26 15:55, 38F
是。 VM以外。 ※ 編輯: pttworld (111.248.172.93), 05/26/2015 15:56:17
文章代碼(AID): #1LOkV_d1 (java)
文章代碼(AID): #1LOkV_d1 (java)