sun.misc.Unsafe和堆外内存
sun.misc.Unsafe類允許您執行許多Java中不應該做的事情,但是在非常特殊的情況下仍然有用。 必須在99%的時間避免這種情況,但是在極少數情況下,這是唯一有意義的解決方案。
這篇文章考慮了它在OpenHFT中的使用方式以及我希望在Java 9中看到的功能。特別地,可以通過這種方式完成訪問大量內存而不影響GC的工作。 只有在Java中才能通過這種方式在進程之間共享內存,而不會產生大量開銷。
分配和釋放堆內存。
public native long allocateMemory(); public native void freeMemory(long address);這兩種方法允許您分配任何大小的堆外內存。 它不限于Integer.MAX_VALUE字節,您會獲得原始內存,可以在其中應用邊界檢查。 例如,Bytes.writeUTF(String)計算編碼字符串的長度,并檢查整個字符串是否適合一次(而不是每個字節)。
Java-Lang使用與DirectByteBuffer用來確保釋放內存相同的內部Cleaner類。 理想情況下,這不會那么內部。
原始訪問內存
public native Xxx getXxx(Object, long offset); // intrinsic public native void putXxx(Object, long offset);// intrinsic在這兩種情況下,處理堆外內存時,Object均為null,并且偏移量只是地址。 這使您可以使用針對JVM的單個機器代碼指令來執行RAW內存訪問,這些指令會威脅到它們作為內在函數。 這顯著提高了內存訪問的性能。
這種原始方法的問題在于,您必須自己管理數據結構中字段的布局。 Java-Lang庫通過允許您定義getter和setter的接口(甚至對于String和enums等對象類型)來解決此問題,它將在運行時生成實現。 即,您可以訪問getter / setter,而無需知道“對象”已脫離堆。
線程安全訪問內存
public native Xxx getVolatileXxx(Object, long offset); // intrinsic public native void putOrderedXxx(Object, long offset); // intrinsic這兩種方法使您可以將惰性字段與惰性集一起使用。 對于設置線程,惰性設置速度更快,但是如果設置得太快,則可能導致同一線程讀取舊值。 解決方案是不要讀取您剛剛編寫的值。
當在進程之間共享數據時,這些方法特別有用。
CAS操作
public native boolean compareAndSwapXxxx(Object, long offset, Xxx expected, Xxx setTo) // intrinsic此方法對于構建鎖定堆至關重要。 特別是在進程之間以線程安全的方式共享數據的最有效方法。 在我對Haswell i7-4500處理器進行的測試中,同一臺計算機上兩個進程的往返延遲通常是這樣。
| TCP協議 | – 9微秒。 |
| 文件鎖 | – 5.5微秒。 |
| 中國科學院 | – 0.12微秒。 |
| 有序寫 | – 0.02微秒(半往返,如果可以使用此模式) |
堆對象分配
public native Object allocateInstance(Class clazz);在反序列化一個類時,您希望按照序列化時的方式重新構造該類中的值。 如JEP 187:序列化2.0所述,這不適用于當前的構造函數,一種解決方法是完全避免構造函數,并創建實例而不調用實例。 這在很大程度上取決于信任您擁有的數據,但是它具有易于使用的優點,并且不假設您擁有哪些構造函數。
結論
經常注意到,在沒有網絡開銷的情況下,嵌入式數據庫可以在延遲方面勝過分布式數據庫。 我相信下一代低延遲數據庫將提供嵌入式性能并在進程之間共享,并且更新和查詢響應時間都將大大低于一微秒。
我認為沒有理由不應該在Java中實現這些功能。 對于Java用戶,本機接口性能最佳,因為它不需要JNI或將世界的C視圖轉換為Java視圖。
翻譯自: https://www.javacodegeeks.com/2014/01/sun-misc-unsafe-and-off-heap-memory.html
總結
以上是生活随笔為你收集整理的sun.misc.Unsafe和堆外内存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓模拟器评测 2021(安卓模拟器评测
- 下一篇: 指定Gradle构建属性