日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 反射操作字段_x86上的Java最终字段没有操作?

發布時間:2023/12/3 java 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 反射操作字段_x86上的Java最终字段没有操作? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

java 反射操作字段

我一直很樂于深入研究多線程編程的細節,并且盡管閱讀了多年的CPU內存一致性模型,無等待和無鎖算法,Java內存模型,實踐中的Java并發性等知識,但我總是很喜歡。等等-我仍然會創建多線程編程錯誤。 總是令人驚奇的謙卑經歷,使我想起這個問題有多復雜。

如果您已經閱讀過JMM,那么您可能會記得,他們加強的領域之一是保證構造函數完成后最終字段的可見性。 例如,

public class ClassA {public final String b;public ClassA(String b) {this.b = b;} } ... ClassA x = new ClassA("hello");

JMM指出,每個線程(甚至構成ClassA實例x的線程除外)都將
始終將 xb視為“ hello”,并且永遠不會看到null值(參考字段的默認值)。

真是太好了! 這意味著我們可以通過將字段標記為final來創建不可變對象,并且任何構造的實例都可以自動在線程之間共享,而無需進行其他工作來保證內存可見性。 ! 不利的一面是,如果未將ClassA.b標記為final,那么您將沒有此類保證。 其他線程可能會觀察到xb ==空結果(如果未使用其他“安全發布”機制來獲得可見性)

當他們創建新的JMM時,每個人都喜歡的JCP成員Doug Lea創建了一個食譜,以幫助JVM開發人員實現新的內存模型規則。 如果閱讀此內容,那么您將看到“規則”狀態,即JIT編譯器應在構造函數返回之前立即發出StoreStore內存屏障。 StoreStore障礙是一種“內存圍欄”。 如果在匯編指令中發出該信息,則意味著在對柵欄進行重新排序之前, 在柵欄之前出現的內存寫之前,不能對內存進行任何寫(存儲)操作。 請注意,它并沒有說明讀取內容,它們可以沿任一方向“跳”柵欄。

那么這是什么意思? 如果考慮一下在調用構造函數時編譯器會執行的操作,那么很好:

String x = new ClassA("hello");get's broken down in to pseudo-code steps of:1. pointer_to_A = allocate memory for ClassA (mark word, class object pointer, one reference field for String b) 2. pointer_to_A.whatever class meta data = ... 3. pointer_to_A.b = address of "hello" string 4. emit a StoreStore memory barrier per the JMM 5. x = pointer_to_A

步驟4的StoreStore屏障可確保任何寫入(例如類元數據和對字段b的寫入)都不會在步驟5中對x進行重新排序。這可以確保x是否對其他任何線程都是可見的-沒有StoreStore內存屏障的情況下,其他線程也無法看到x。如果沒有StoreStore內存屏障,則可以對第3步和第5步進行重新排序,并且在寫入xb和另一個cpu之前可能會顯示對x的主內存寫入內核可以觀察到pointer_to_A.b為0(空),這將違反JMM。

好消息! 但是,如果您看一看該菜譜,就會發現一些有趣的事情:(1)很多人在許多處理器體系結構上編寫JVM! (2)x86上的所有*存儲屏障都是無操作的,除了StoreLoad屏障! 這意味著在x86上,上面的此StoreStore內存屏障為空操作,因此不會為此發出任何程序集。 什么也沒做! 這是因為x86的內存模型是強大的 “總存儲排序”(TSO)。 X86確保觀察到所有內存寫入,就像它們都是以相同順序進行的一樣。 因此,由于TSO的原因,寫入5永遠不會出現在任何其他線程的3之前,并且不需要發出內存隔離。 其他cpu體系結構的內存模型較弱,無法保證這種性能,因此需要StoreStore內存圍墻。 請注意,較弱的內存模型雖然可能更難編程或較不直觀,但通常要快得多,因為cpu可以對事物進行重新排序以更有效地使用緩存寫入并減少緩存一致性工作。

顯然,您應該繼續按照JMM編寫正確的代碼。 但是,這也意味著(不幸或幸運的是)如果您在x86上運行,忘記它不會導致錯誤……就像我在工作中所做的那樣。

為了真正地鉆研這個家并確保沒有食譜中可能沒有描述的其他副作用,我按此處所述運行了x86程序集輸出程序,并捕獲了為ClassA調用構造函數的輸出(最后一個在引用類型字段)和ClassB的構造函數,該類與ClassA相同,除了在類成員上沒有final關鍵字之外。 x86程序集的輸出是相同的 。 因此,從JIT角度來看,在x86(非鈦合金,非arm等)上,final關鍵字沒有任何影響。

如果您想知道匯編代碼的外觀,則如下所示。 請注意,沒有任何鎖定說明。 當Oracle的7u25 JRE發出x86 StoreLoad內存隔離柵時,它是通過發出鎖addl $ 0x0,(%rsp)來完成的,該鎖只會向堆棧指針添加零(無操作, 但由于其被鎖定),因此具有完全柵欄(符合StoreLoad柵欄的條件)。 x86中有幾種導致完全隔離的效果的方法,這些方法在OpenJDK郵件列表中進行了討論。 他們觀察到至少在nehelem intel上,鎖添加0是最緊湊/有效的空間。

0x00007f152c020c60: mov %eax,-0x14000(%rsp)0x00007f152c020c67: push %rbp0x00007f152c020c68: sub $0x20,%rsp ;*synchronization entry; - com.argodata.match.profiling.FinalConstructorMain::callA@-1 (line 60)0x00007f152c020c6c: mov %rdx,(%rsp)0x00007f152c020c70: mov %esi,%ebp0x00007f152c020c72: mov 0x60(%r15),%rax0x00007f152c020c76: mov %rax,%r100x00007f152c020c79: add $0x18,%r100x00007f152c020c7d: cmp 0x70(%r15),%r100x00007f152c020c81: jae 0x00007f152c020cd60x00007f152c020c83: mov %r10,0x60(%r15)0x00007f152c020c87: prefetchnta 0xc0(%r10)0x00007f152c020c8f: mov $0x8356f3d0,%r11d ; {oop('com/argodata/match/profiling/FinalConstructorMain$ClassA')}0x00007f152c020c95: mov 0xb0(%r11),%r100x00007f152c020c9c: mov %r10,(%rax)0x00007f152c020c9f: movl $0x8356f3d0,0x8(%rax) ; {oop('com/argodata/match/profiling/FinalConstructorMain$ClassA')}0x00007f152c020ca6: mov %r12d,0x14(%rax) ;*new ; - com.argodata.match.profiling.FinalConstructorMain::callA@0 (line 60)0x00007f152c020caa: mov %ebp,0xc(%rax) ;*putfield a; - com.argodata.match.profiling.FinalConstructorMain$ClassA::@6 (line 17); - com.argodata.match.profiling.FinalConstructorMain::callA@6 (line 60)0x00007f152c020cad: mov (%rsp),%r100x00007f152c020cb1: mov %r10d,0x10(%rax) ;*new ; - com.argodata.match.profiling.FinalConstructorMain::callA@0 (line 60)0x00007f152c020cb5: mov %rax,%r100x00007f152c020cb8: shr $0x9,%r100x00007f152c020cbc: mov $0x7f152b765000,%r110x00007f152c020cc6: mov %r12b,(%r11,%r10,1) ;*synchronization entry; - com.argodata.match.profiling.FinalConstructorMain::callA@-1 (line 60)0x00007f152c020cca: add $0x20,%rsp0x00007f152c020cce: pop %rbp0x00007f152c020ccf: test %eax,0x9fb932b(%rip) # 0x00007f1535fda000; {poll_return}0x00007f152c020cd5: retq 0x00007f152c020cd6: mov $0x8356f3d0,%rsi ; {oop('com/argodata/match/profiling/FinalConstructorMain$ClassA')}0x00007f152c020ce0: xchg %ax,%ax0x00007f152c020ce3: callq 0x00007f152bfc51e0 ; OopMap{[0]=Oop off=136};*new ; - com.argodata.match.profiling.FinalConstructorMain::callA@0 (line 60); {runtime_call}0x00007f152c020ce8: jmp 0x00007f152c020caa ;*new; - com.argodata.match.profiling.FinalConstructorMain::callA@0 (line 60)0x00007f152c020cea: mov %rax,%rsi0x00007f152c020ced: add $0x20,%rsp0x00007f152c020cf1: pop %rbp0x00007f152c020cf2: jmpq 0x00007f152bfc8920 ; {runtime_call}

參考: x86上的Java final字段是否沒有操作? 來自我們的JCG合作伙伴史蒂夫·阿什(Steve Ash),來自“多杯咖啡”博客。

翻譯自: https://www.javacodegeeks.com/2013/11/java-final-fields-on-x86-a-no-op.html

java 反射操作字段

總結

以上是生活随笔為你收集整理的java 反射操作字段_x86上的Java最终字段没有操作?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。