netty 中 直接內(nèi)存和堆內(nèi)存以及拷貝

這是一個來自知乎上一個問題

  • DirectBuffer 屬于堆外存房蝉,那應(yīng)該還是屬于用戶內(nèi)存,而不是內(nèi)核內(nèi)存竹宋?
  • FileChannel 的read(ByteBuffer dst)函數(shù),write(ByteBuffer src)函數(shù)中敞贡,如果傳入的參數(shù)是HeapBuffer類型,則會臨時申請一塊DirectBuffer,進(jìn)行數(shù)據(jù)拷貝,而不是直接進(jìn)行數(shù)據(jù)傳輸哗总,這是出于什么原因?

Java NIO中的direct buffer(主要是DirectByteBuffer)其實(shí)是分兩部分的:

image.png

其中 DirectByteBuffer 自身是一個Java對象倍试,在Java堆中讯屈;而這個對象中有個long類型字段address,記錄著一塊調(diào)用 malloc() 申請到的native memory易猫。

問題1

DirectByteBuffer 自身是(Java)堆內(nèi)的耻煤,它背后真正承載數(shù)據(jù)的buffer是在(Java)堆外——native memory中的具壮。這是 malloc() 分配出來的內(nèi)存准颓,是用戶態(tài)的。

問題 2

//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);
        }
    }

這里其實(shí)是在遷就OpenJDK里的HotSpot VM的一點(diǎn)實(shí)現(xiàn)細(xì)節(jié)棺妓。HotSpot VM里的GC除了CMS之外都是要移動對象的攘已,是所謂“compacting GC”。如果要把一個Java里的 byte[] 對象的引用傳給native代碼怜跑,讓native代碼直接訪問數(shù)組的內(nèi)容的話样勃,就必須要保證native代碼在訪問的時候這個 byte[] 對象不能被移動吠勘,也就是要被“pin”(釘)住∠靠簦可惜HotSpot VM出于一些取舍而決定不實(shí)現(xiàn)單個對象層面的object pinning剧防,要pin的話就得暫時禁用GC——也就等于把整個Java堆都給pin住。HotSpot VM對JNI的Critical系A(chǔ)PI就是這樣實(shí)現(xiàn)的辫樱。這用起來就不那么順手峭拘。所以 Oracle/Sun JDK / OpenJDK 的這個地方就用了點(diǎn)繞彎的做法。它假設(shè)把 HeapByteBuffer 背后的 byte[] 里的內(nèi)容拷貝一次是一個時間開銷可以接受的操作狮暑,同時假設(shè)真正的I/O可能是一個很慢的操作鸡挠。于是它就先把 HeapByteBuffer 背后的 byte[] 的內(nèi)容拷貝到一個 DirectByteBuffer 背后的native memory去,這個拷貝會涉及 sun.misc.Unsafe.copyMemory() 的調(diào)用搬男,背后是類似 memcpy() 的實(shí)現(xiàn)拣展。這個操作本質(zhì)上是會在整個拷貝過程中暫時不允許發(fā)生GC的,雖然實(shí)現(xiàn)方式跟JNI的Critical系A(chǔ)PI不太一樣缔逛。(具體來說是 Unsafe.copyMemory() 是HotSpot VM的一個intrinsic方法备埃,中間沒有safepoint所以GC無法發(fā)生)。然后數(shù)據(jù)被拷貝到native memory之后就好辦了译株,就去做真正的I/O瓜喇,把 DirectByteBuffer 背后的native memory地址傳給真正做I/O的函數(shù)。這邊就不需要再去訪問Java對象去讀寫要做I/O的數(shù)據(jù)了歉糜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載乘寒,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末匪补,一起剝皮案震驚了整個濱河市伞辛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夯缺,老刑警劉巖蚤氏,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異踊兜,居然都是意外死亡竿滨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門捏境,熙熙樓的掌柜王于貴愁眉苦臉地迎上來于游,“玉大人,你說我怎么就攤上這事垫言》“” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵筷频,是天一觀的道長蚌成。 經(jīng)常有香客問我前痘,道長,這世上最難降的妖魔是什么担忧? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任芹缔,我火速辦了婚禮,結(jié)果婚禮上瓶盛,老公的妹妹穿的比我還像新娘乖菱。我一直安慰自己,他們只是感情好蓬网,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布窒所。 她就那樣靜靜地躺著,像睡著了一般帆锋。 火紅的嫁衣襯著肌膚如雪吵取。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天锯厢,我揣著相機(jī)與錄音皮官,去河邊找鬼。 笑死实辑,一個胖子當(dāng)著我的面吹牛捺氢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剪撬,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼摄乒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了残黑?” 一聲冷哼從身側(cè)響起馍佑,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梨水,沒想到半個月后拭荤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疫诽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年舅世,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奇徒。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡雏亚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出逼龟,到底是詐尸還是另有隱情评凝,我是刑警寧澤追葡,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布腺律,位于F島的核電站奕短,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏匀钧。R本人自食惡果不足惜翎碑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望之斯。 院中可真熱鬧日杈,春花似錦、人聲如沸佑刷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘫絮。三九已至涨冀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間麦萤,已是汗流浹背鹿鳖。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留壮莹,地道東北人翅帜。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像命满,于是被迫代替她去往敵國和親涝滴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容