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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java heap buffer direct buffer_java NIO - DirectBuffer 和 HeapBuffer

發(fā)布時(shí)間:2025/3/11 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java heap buffer direct buffer_java NIO - DirectBuffer 和 HeapBuffer 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

問(wèn)題 :

DirectBuffer 屬于堆外存,那應(yīng)該還是屬于用戶內(nèi)存,而不是內(nèi)核內(nèi)存?

FileChannel 的read(ByteBuffer dst)函數(shù),write(ByteBuffer src)函數(shù)中,如果傳入的參數(shù)是HeapBuffer類(lèi)型,則會(huì)臨時(shí)申請(qǐng)一塊DirectBuffer,進(jìn)行數(shù)據(jù)拷貝,而不是直接進(jìn)行數(shù)據(jù)傳輸,這是出于什么原因?

DirectBuffer

Java | native

|

DirectByteBuffer | malloc'd

[ address ] -+-> [ data ]

|

DirectByteBuffer 自身是一個(gè)Java對(duì)象,在Java堆中;而這個(gè)對(duì)象中有個(gè)long類(lèi)型字段address,記錄著一塊調(diào)用 malloc() 申請(qǐng)到的native memory。DirectByteBuffer 自身是(Java)堆內(nèi)的,它背后真正承載數(shù)據(jù)的buffer是在(Java)堆外——native memory中的。這是 malloc() 分配出來(lái)的內(nèi)存,是用戶態(tài)的。(來(lái)自參考文章R大的回答)

DirectBuffer 和 HeapBuffer

兩個(gè)都是Buffer ,不同的是前者使用的是堆外內(nèi)存,后者時(shí)候的是 JVM 堆內(nèi)內(nèi)存。在使用 FileChannel 讀寫(xiě)的時(shí)候內(nèi)部實(shí)現(xiàn)就有點(diǎn)不同了。以下是FileChannel使用代碼

public static void main(String[] args) throws Exception{

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");

FileChannel channel = aFile.getChannel();

String newData = "New String to write to file..." + System.currentTimeMillis();

// HeapByteBuffer

ByteBuffer buf = ByteBuffer.allocate(48);

// DirectByteBuffer

ByteBuffer dirctBuf = ByteBuffer.allocateDirect(48);

buf.clear();

buf.put(newData.getBytes());

buf.flip();

while(buf.hasRemaining()) {

channel.write(buf);

}

}

//讀取地址

FileInputStream fis = new FileInputStream("C:\\CloudMusic\\Circadian Eyes - Ferris Wheel.mp3");

//寫(xiě)出地址

FileOutputStream fos = new FileOutputStream("D:\\etc\\cas\\logs\\cas_audit.log");

FileChannel fc = fis.getChannel();

MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());

//回刷回磁盤(pán)

mbb.flip();

fos.flush();

fc.close();

fis.close();

如果上面的代碼channel.write傳入的參數(shù)是HeapBuffer類(lèi)型,則會(huì)臨時(shí)申請(qǐng)一塊DirectBuffer,將HeapBuffer中的數(shù)據(jù)進(jìn)行數(shù)據(jù)拷貝到堆外內(nèi)存,然后剩下就是對(duì)DirectBuffer進(jìn)行IO操作,為什么直接使用HeapBuffer拷貝數(shù)據(jù)到內(nèi)核中,然后進(jìn)行IO操作呢?這是因?yàn)槿绻岩粋€(gè)Java里的 byte[] 對(duì)象的引用傳給native代碼,讓native代碼直接訪問(wèn)數(shù)組的內(nèi)容的話,就必須要保證native代碼在訪問(wèn)的時(shí)候這個(gè) byte[] 對(duì)象不能被移動(dòng),也就是要被“pin”(釘)住。而虛擬機(jī)的GC 算法會(huì)移動(dòng)對(duì)象,導(dǎo)致地址會(huì)變化,那么后續(xù)就會(huì)產(chǎn)生錯(cuò)誤。詳細(xì)的見(jiàn)參考資料R大的回答。 ?OpenJDK的 sun.nio.ch.IOUtil.write(FileDescriptor fd, ByteBuffer src, long position, NativeDispatcher nd) 的實(shí)現(xiàn)。

static int write(FileDescriptor fd, ByteBuffer src, long position,

NativeDispatcher nd)

throws IOException

{

if (src instanceof DirectBuffer)

return writeFromNativeBuffer(fd, src, position, nd);

// Substitute a native buffer

int pos = src.position();

int lim = src.limit();

assert (pos <= lim);

int rem = (pos <= lim ? lim - pos : 0);

ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);

try {

bb.put(src);

bb.flip();

// Do not update src until we see how many bytes were written

src.position(pos);

int n = writeFromNativeBuffer(fd, bb, position, nd);

if (n > 0) {

// now update src

src.position(pos + n);

}

return n;

} finally {

Util.offerFirstTemporaryDirectBuffer(bb);

}

}

MappedByteBuffer

MappedByteBuffer 是 DirectBuffer 的父類(lèi),它的讀寫(xiě)性能比HeapByteBuffer要高(不然FileChannel 內(nèi)部實(shí)現(xiàn)中也不會(huì)用DirectByteBuffer進(jìn)行操作)。MappedByteBuffer 內(nèi)部原理主要和操作系統(tǒng)的虛擬存儲(chǔ)有關(guān),更加直接的聯(lián)系就是頁(yè)表相關(guān)的知識(shí),先閱讀以下這篇文章。

補(bǔ)充

關(guān)于 Heap memory 和 Native memory的解釋,來(lái)自stackoverflow

Heap memory: memory within the JVM process that is managed by the JVM to represent Java objects

Native memory/Off-heap: is memory allocated within the processes address space that is not within the heap.

Direct memory: is similar to native, but also implies that an underlying buffer within the hardware is being shared. For example buffer within the network adapter or graphics display. The goal here is to reduce the number of times the same bytes is being copied about in memory.

Finally, depending upon the OS then extra native allocations (assigning of the memory address space) can be carried out via Unsafe alloc and/or by memory mapping a file. Memory mapping a file is especially interesting as it can easily allocate more memory than the machine currently has as physical ram. Also note, that the total address space limit is restricted by the size of a pointer being used, a 32bit pointer cannot go outside of 4GB. Period.

參考資料

https://www.zhihu.com/question/57374068 (推薦一看)

總結(jié)

以上是生活随笔為你收集整理的java heap buffer direct buffer_java NIO - DirectBuffer 和 HeapBuffer的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。