成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊 Netty 零拷貝等技術對于內存方面的優化

開發
本文將直接從源碼的角度分析一下 Netty 對于內存方面的使用技巧,希望對你有所啟發。

Netty通過巧妙的內存使用技巧盡可能節約內存空間,進而減少java中Full gc的STW的時間,由此間接的提升了程序的性能,本文也將直接從源碼的角度分析一下Netty對于內存方面的使用技巧,希望對你有所啟發。

使用基本類型替代包裝類

內存空間算是寶貴的系統資源,為了提升CPU加載數據效率以及節約內存空間,對于某些常見的基本數據類型,Netty都是能省則省,最直接的落地方案就是使用基本類型替代包裝類。

這其中totalPendingSize這個變量,它用于記錄那些待處理的數據,為了節約內存空間,記錄大小的類型是long而非Long,通過這種方式避免了創建java對象(java對象包含對象頭的信息,相比基本類型更占用內存空間):

對此我們也給出這個變量的定義:

@SuppressWarnings("UnusedDeclaration")
    private volatile long totalPendingSize;

又因為該字段需要保證線程安全,所以Netty設計者在此基礎上又將其設置為AtomicLong原子類型,通過static關鍵字加以修飾,使所有實例共享一個變量,從而避免沒必要的創建開銷和并發安全:

對此我們也給出源碼示例,即位于ChannelOutboundBuffer變量定義的位置:

//通過AtomicLongFieldUpdater修飾totalPendingSize
  private static final AtomicLongFieldUpdater<ChannelOutboundBuffer> TOTAL_PENDING_SIZE_UPDATER =
            AtomicLongFieldUpdater.newUpdater(ChannelOutboundBuffer.class, "totalPendingSize");

動態內存調整

除上述內存使用技巧以外,netty在進行內存分配時也用到的動態調整的使用技巧,該設計理念比較簡單,按照空間與分配思想:后續使用的內存大小大概率是等同于本次使用的空間大小,所以Netty在調用record進行內存分配時,如果發現縮小空間依然可以滿足要求,則進行縮容,反之進行擴容,由此得到一個盡可能節約內存空間且能滿足業務要求的數值:

private void record(int actualReadBytes) {
            //若實際需要的空間 <= 預縮小達到的尺寸,則對nextReceiveBufferSize進行縮減
            if (actualReadBytes <= SIZE_TABLE[max(0, index - INDEX_DECREMENT)]) {
                if (decreaseNow) {
                    index = max(index - INDEX_DECREMENT, minIndex);
                    nextReceiveBufferSize = SIZE_TABLE[index];
                    decreaseNow = false;
                } else {
                    decreaseNow = true;
                }
            } else if (actualReadBytes >= nextReceiveBufferSize) {//如果所需空間大于nextReceiveBufferSize,則進行擴容
                index = min(index + INDEX_INCREMENT, maxIndex);
                nextReceiveBufferSize = SIZE_TABLE[index];
                decreaseNow = false;
            }
        }

應用層面的zero-copy

內存拷貝也是存在一定的時間開銷,例如我們現在有一個字符串的數據需要將byte1和byte2拼接起來才能得到,按照傳統的實現思路,我們需要開發一個足夠容納byte1和byte2的內存空間,然后將byte1和byte2一并寫入,這種做法有著如下耗時點:

  • 開辟內存空間所占用的時間。
  • 將byte1內存新開辟空間的耗時。
  • 將byte2寫入新開辟的內存空間耗時。

而Netty則不是這樣做,它的設計思路是直接將兩個數組,邏輯上組合,即通過一個數組指向這兩個引用,從邏輯上視為一個整體,而不是物理操作上的組合:

對此我們給出CompositeByteBuf的addComponent0方法,可以看到對于需要組合的數據buffer,它會通過addComp方法將這個ByteBuf 存到CompositeByteBuf底層的數組中,由此保證數據邏輯上的一致:

private int addComponent0(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
        assert buffer != null;
        boolean wasAdded = false;
        try {
            checkComponentIndex(cIndex);

            //將其包裝為Component 
            Component c = newComponent(ensureAccessible(buffer), 0);
            int readableBytes = c.length();

           //......
   //添加到CompositeByteBuf底層的components數組中,通過邏輯完成組合
            addComp(cIndex, c);
           //......
            return cIndex;
        } finally {
          //......
        }
    }

//添加到components數組中保證邏輯上的一致
private void addComp(int i, Component c) {
        //......
        components[i] = c;
    }

使用堆外內存

將數據存放在JVM非堆內存空間,通過減少沒必要的GC確保操作和執行性能的高效,這也是Netty中對于內存方面的優化,這其中最經典的就是PooledHeapByteBuf,它直接操作的就是堆外內存的數據:

對此我們也給處PooledDirectByteBuf 獲取直接內存的源碼實現:

//從內存池中獲取直接內存空間返回給用戶使用
  static PooledDirectByteBuf newInstance(int maxCapacity) {
        PooledDirectByteBuf buf = RECYCLER.get();
        buf.reuse(maxCapacity);
        return buf;
    }

需要補充的是,這種做法也存在的一定的風險:

  • 創建速度慢。
  • 存放在非堆內存空間,使用不當可能造成內存泄漏。

內存池化復用

上文的堆內存就是PooledHeapByteBuf即池化過的內存,通過池化:

  • 保證對象復用,減小沒必要的創建開銷。
  • 提升程序并發執行性能。

對此我們給出相應的源碼實現:

//初始化直接內存池化工廠RECYCLER 
private static final ObjectPool<PooledDirectByteBuf> RECYCLER = ObjectPool.newPool(
            new ObjectCreator<PooledDirectByteBuf>() {
        @Override
        public PooledDirectByteBuf newObject(Handle<PooledDirectByteBuf> handle) {
            return new PooledDirectByteBuf(handle, 0);
        }
    });


//從內存池中獲取直接內存空間返回給用戶使用
  static PooledDirectByteBuf newInstance(int maxCapacity) {
    //從內存池中獲取直接內存空間
        PooledDirectByteBuf buf = RECYCLER.get();
        buf.reuse(maxCapacity);
        return buf;
    }

對jdk零拷貝的封裝

我們在上述所講的零復制更多強調的是應用層面上的零復制,也就是通過減少應用層面上數據的拷貝提升程序的執行效率。實際上Netty也有基于操作系統層面的零拷貝實現,這其中最典型的實現就是DefaultFileRegion的transferTo函數,它底層調用JDK自帶的NIO零拷貝方法transferTo實現當前文件數據通過sendfile調用傳輸到socket通道中,由此避免數據傳輸時多次切態、內核緩沖區和用戶緩沖區來回拷貝的開銷:

對此我們也給出DefaultFileRegion類中transferTo的源碼,可以看到其底層就是將JDK默認的NIO零拷貝方法進行封裝,將DefaultFileRegion封裝的FileChannel 的文件數據拷貝到target的文件通道中,其底層就用到內核函數sendfile:

private FileChannel file;

 @Override
    public long transferTo(WritableByteChannel target, long position) throws IOException {
        //......

        long written = file.transferTo(this.position + position, count, target);
        if (written > 0) {
            transferred += written;
        } else if (written == 0) {
           //......
        }
        return written;
    }
責任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關推薦

2024-11-22 00:09:15

2016-11-23 19:09:39

javanetty

2018-08-15 10:29:58

NettyJDK內存

2024-06-07 08:10:14

Netty操作系統零拷貝

2022-09-23 08:47:01

DMA網卡CPU

2022-05-05 13:57:43

Buffer設備MYSQL

2022-05-16 08:22:37

零拷貝Netty

2009-12-30 17:30:43

EPON技術

2021-06-08 07:45:44

Go語言優化

2024-12-26 17:04:47

2023-12-02 20:41:32

內存kube

2020-08-03 10:53:25

存儲容器虛擬機

2021-08-26 06:57:53

零拷貝技術磁盤

2020-07-06 15:10:05

Linux拷貝代碼

2020-07-23 15:40:54

Linux零拷貝文件

2022-09-27 13:34:49

splice零拷貝原理

2013-04-27 17:09:29

安全管理IT技術

2010-09-02 10:32:41

2023-04-17 16:40:12

能源管理綠色數字化轉型

2024-11-28 10:40:26

零拷貝技術系統
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 99爱在线免费观看 | 亚洲看片网站 | 亚洲一二三区精品 | 欧美日韩国产精品 | 免费黄色录像视频 | 国产黄色电影 | 91精品国产一区二区三区 | 亚洲精品免费在线 | 国产精品成人在线播放 | 91精品国产91久久综合桃花 | 日韩成人 | 日本不卡免费新一二三区 | 亚洲精品久久久一区二区三区 | 色狠狠一区 | 在线看中文字幕 | 九九99九九精彩46 | 精品国产乱码久久久久久1区2区 | 午夜久久久 | 毛片免费观看视频 | 国产精品精品视频一区二区三区 | 日韩淫片免费看 | 一区二区三区四区在线播放 | 日本在线免费看最新的电影 | 免费1区2区3区 | 日本特黄a级高清免费大片 国产精品久久性 | 日本精品免费在线观看 | 欧美精品综合在线 | 日韩不卡三区 | 亚洲人人| 欧美精品久久久 | 国产成人精品一区二 | 91久色| 国产一区二区在线免费观看 | 羞羞的视频在线观看 | 视频一区在线 | 日本在线黄色 | 91免费看片 | 99精品在线 | 精品国产乱码久久久久久中文 | 精品日韩一区二区三区av动图 | 国产一二区免费视频 |