3 回答

TA貢獻1859條經驗 獲得超6個贊
羅恩·希切斯(Ron Hitches)在他的著作《Java NIO》中似乎提供了我認為可以很好地回答您的問題的答案:
操作系統在內存區域上執行I / O操作。就操作系統而言,這些存儲區是連續的字節序列。因此,只有字節緩沖區才有資格參與I / O操作就不足為奇了。還記得操作系統將直接訪問該進程的地址空間,在本例中為JVM進程,以傳輸數據。這意味著作為I / O操作目標的存儲區必須是連續的字節序列。在JVM中,字節數組可能不會連續存儲在內存中,否則垃圾回收器可以隨時移動它。數組是Java中的對象,數據在該對象中的存儲方式可能因一個JVM實現而異。
因此,引入了直接緩沖區的概念。直接緩沖區旨在與通道和本機I / O例程進行交互。他們盡最大努力將字節元素存儲在通道可用于直接訪問或原始訪問的存儲區中,方法是使用本機代碼告訴操作系統直接耗盡或填充存儲區。
直接字節緩沖區通常是I / O操作的最佳選擇。通過設計,它們支持JVM可用的最有效的I / O機制。非直接字節緩沖區可以傳遞給通道,但是這樣做可能會導致性能下降。非直接緩沖區通常不可能成為本機I / O操作的目標。如果將非直接ByteBuffer對象傳遞給通道進行寫入,則該通道可能會在每次調用時隱式執行以下操作:
創建一個臨時直接ByteBuffer對象。
將非直接緩沖區的內容復制到臨時緩沖區。
使用臨時緩沖區執行低級I / O操作。
臨時緩沖區對象超出范圍,最終被垃圾回收。
這可能會導致每個I / O上的緩沖區復制和對象流失,這正是我們想要避免的事情。但是,根據實現的不同,情況可能還不錯。運行時可能會緩存和重用直接緩沖區,或者執行其他巧妙的技巧來提高吞吐量。如果您只是創建用于一次性使用的緩沖區,則差異并不明顯。另一方面,如果您將在高性能場景中重復使用緩沖區,則最好分配直接緩沖區并重新使用它們。
直接緩沖區是I / O的最佳選擇,但創建起來可能會比非直接字節緩沖區昂貴。直接緩沖區使用的內存是通過繞過標準JVM堆調用本地特定于操作系統的代碼來分配的。根據主機操作系統和JVM的實現,設置和拆除直接緩沖區可能比堆駐留緩沖區昂貴得多。直接緩沖區的內存存儲區不受垃圾回收的影響,因為它們在標準JVM堆之外。
使用直接緩沖區與非直接緩沖區的性能折衷可能因JVM,操作系統和代碼設計而有很大差異。通過在堆之外分配內存,您可能會使您的應用程序受到JVM不了解的其他壓力。發揮其他活動部件的作用時,請確保達到預期的效果。我建議使用舊的軟件準則:首先使其運行,然后使其快速運行。不必太擔心預先優化;首先專注于正確性。JVM實現可能能夠執行緩沖區緩存或其他優化,從而為您提供所需的性能,而無需您付出很多不必要的努力。

TA貢獻1942條經驗 獲得超3個贊
因為DirectByteBuffers是OS級別的直接內存映射
他們不是。它們只是正常的應用程序進程內存,而在Java GC期間不會進行重定位,從而極大地簡化了JNI層中的內容。您所描述的適用于MappedByteBuffer
。
使用get / put調用可以更快地執行
結論并非來自前提。前提是假的;結論也是錯誤的。他們更快一旦你的JNI層內,如果你正在閱讀和同寫DirectByteBuffer
他們是多快,因為數據從來沒有越過邊界JNI在所有。

TA貢獻1829條經驗 獲得超9個贊
最好自己做測量??焖俚拇鸢杆坪跏?,從allocateDirect()
緩沖區發送所需的時間比allocate()
變體(測試為將文件復制到/ dev / null)要少25%到75%,具體取決于大小,但是分配本身可能會明顯變慢(即使100倍)。
添加回答
舉報