Netty学习——源码篇11 Netty非池化内存分配 备份

news/2024/4/17 7:07:33

1 堆内内存的分配

        现在来看UnpooledByteBufAllocator的内存分配原理。首先是heapBuffer的分配逻辑,newHeapBuffer方法的代码如下:

    @Overrideprotected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity): new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);}

        通过调用PlatformDependent.hasUnsafe()方法来判断操作系统是否支持Unsafe,如果支持Unsafe则创建UnpooledUnsafeHeapByteBuf类,否则创建UnpooledHeapByteBuf类。先看一下UnpooledUnsafeHeapByteBuf的构造器会进行哪些操作,代码如下:

final class UnpooledUnsafeHeapByteBuf extends UnpooledHeapByteBuf {/*** Creates a new heap buffer with a newly allocated byte array.** @param initialCapacity the initial capacity of the underlying byte array* @param maxCapacity the max capacity of the underlying byte array*/UnpooledUnsafeHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {super(alloc, initialCapacity, maxCapacity);}
}

        发现UnpooledUnsafeHeapByteBuf继承了UnpooledHeapByte,并且在UnpooledUnsafeHeapByteBuf的构造器中直接调用了super方法,也就是其父类UnpooledHeapByte的构造方法。看一下UnpooledHeapByte的构造方法。

public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {private final ByteBufAllocator alloc;byte[] array;private ByteBuffer tmpNioBuf;/*** Creates a new heap buffer with a newly allocated byte array.** @param initialCapacity the initial capacity of the underlying byte array* @param maxCapacity the max capacity of the underlying byte array*/protected UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {this(alloc, new byte[initialCapacity], 0, 0, maxCapacity);}protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {this(alloc, initialArray, 0, initialArray.length, maxCapacity);}private UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) {super(maxCapacity);if (alloc == null) {throw new NullPointerException("alloc");}if (initialArray == null) {throw new NullPointerException("initialArray");}if (initialArray.length > maxCapacity) {throw new IllegalArgumentException(String.format("initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity));}this.alloc = alloc;setArray(initialArray);setIndex(readerIndex, writerIndex);}}

        其中调用了一个关键方法就是setArray()方法。这个方法的功能非常简单,就是把默认分配的数组new byte[initialCapacity]赋值给全局变量initialArray数组。

    private void setArray(byte[] initialArray) {array = initialArray;tmpNioBuf = null;}

        紧接着调用setIndex方法。

    @Overridepublic ByteBuf setIndex(int readerIndex, int writerIndex) {if (readerIndex < 0 || readerIndex > writerIndex || writerIndex > capacity()) {throw new IndexOutOfBoundsException(String.format("readerIndex: %d, writerIndex: %d (expected: 0 <= readerIndex <= writerIndex <= capacity(%d))",readerIndex, writerIndex, capacity()));}setIndex0(readerIndex, writerIndex);return this;}final void setIndex0(int readerIndex, int writerIndex) {this.readerIndex = readerIndex;this.writerIndex = writerIndex;}

        最终setIndex0()方法中初始化readerIndex属性和writerIndex属性。

        既然UnpooledUnsafeHeapByteBuf和UnpooledHeapByteBuf调用的都是UnpooledHeapByteBuf的构造方法,那么他们之间到底有什么区别呢?根本区别在于I/O的读写,分别来看它们的getByte()方法,了解二者的区别。

        先看UnpooledHeapByteBuf的getByte()方法的实现代码。

    @Overridepublic byte getByte(int index) {ensureAccessible();return _getByte(index);}@Overrideprotected byte _getByte(int index) {return HeapByteBufUtil.getByte(array, index);}

        可以看到,最终调用的是HeapByteBufUtil.getByte(array, index)方法。

    static byte getByte(byte[] memory, int index) {return memory[index];}

        getByte()这个方法中的处理逻辑非常简单,就是根据index索引直接从数组中取值。接着来看UnpooledUnsafeHeapByteBuf的getByte()方法。

    @Overridepublic byte getByte(int index) {checkIndex(index);return _getByte(index);}@Overrideprotected byte _getByte(int index) {return UnsafeByteBufUtil.getByte(array, index);}static byte getByte(byte[] array, int index) {return PlatformDependent.getByte(array, index);}

        可以看到,最终调用的是UnsafeByteBufUtil.getByte(array, index)的方法。通过这样对比代码,已经基本了解UnpooledUnsafeHeapByteBuf和UnpooledHeapByteBuf的区别了。

2 堆外内存的分配

        再回到UnpooledHeapByteBuf的newDirectBuffer方法,代码如下:

    @Overrideprotected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {ByteBuf buf = PlatformDependent.hasUnsafe() ?UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);return disableLeakDetector ? buf : toLeakAwareBuffer(buf);}

    这段代码可以看出,如果支持Unsafe则调用UnsafeByteBufUtil.newUnsafeDirectByteBuf,否则创建UnpooledDirectByteBuf对象。看一下UnpooledDirectByteBuf构造器。

public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {private final ByteBufAllocator alloc;private ByteBuffer buffer;private ByteBuffer tmpNioBuf;private int capacity;private boolean doNotFree;/*** Creates a new direct buffer.** @param initialCapacity the initial capacity of the underlying direct buffer* @param maxCapacity     the maximum capacity of the underlying direct buffer*/protected UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {super(maxCapacity);if (alloc == null) {throw new NullPointerException("alloc");}if (initialCapacity < 0) {throw new IllegalArgumentException("initialCapacity: " + initialCapacity);}if (maxCapacity < 0) {throw new IllegalArgumentException("maxCapacity: " + maxCapacity);}if (initialCapacity > maxCapacity) {throw new IllegalArgumentException(String.format("initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));}this.alloc = alloc;setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));}
}

        首先调用ByteBuffer.allocateDirect.allocatoDirect()通过JDK底层分配了一个直接缓冲区,然后传给setByteBuffer方法。继续跟进,代码如下。

    private void setByteBuffer(ByteBuffer buffer) {ByteBuffer oldBuffer = this.buffer;if (oldBuffer != null) {if (doNotFree) {doNotFree = false;} else {freeDirect(oldBuffer);}}this.buffer = buffer;tmpNioBuf = null;capacity = buffer.remaining();}

         上面代码可以看到,setByteBuffer方法主要做了一次赋值。继续看UnsafeByteBufUtil.newUnsafeDirectByteBuf()方法的逻辑。

static UnpooledUnsafeDirectByteBuf newUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {if (PlatformDependent.useDirectBufferNoCleaner()) {return new UnpooledUnsafeNoCleanerDirectByteBuf(alloc, initialCapacity, maxCapacity);}return new UnpooledUnsafeDirectByteBuf(alloc, initialCapacity, maxCapacity);}

        这个方法返回了一个UnpooledUnsafeDirectByteBuf对象。下面继续来看UnpooledUnsafeDirectByteBuf构造器中的代码。

protected UnpooledUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {super(maxCapacity);if (alloc == null) {throw new NullPointerException("alloc");}if (initialCapacity < 0) {throw new IllegalArgumentException("initialCapacity: " + initialCapacity);}if (maxCapacity < 0) {throw new IllegalArgumentException("maxCapacity: " + maxCapacity);}if (initialCapacity > maxCapacity) {throw new IllegalArgumentException(String.format("initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));}this.alloc = alloc;setByteBuffer(allocateDirect(initialCapacity), false);}

          UnpooledUnsafeDirectByteBuf构造器的逻辑和UnpooledDirectByteBuf构造器的逻辑是相似的,其setByteBuffer方法的实现代码如下:

final void setByteBuffer(ByteBuffer buffer, boolean tryFree) {if (tryFree) {ByteBuffer oldBuffer = this.buffer;if (oldBuffer != null) {if (doNotFree) {doNotFree = false;} else {freeDirect(oldBuffer);}}}this.buffer = buffer;memoryAddress = PlatformDependent.directBufferAddress(buffer);tmpNioBuf = null;capacity = buffer.remaining();}

        同样还是先保存在JDK底层创建的Buffer,接下来有个很重要的操作就是调用PlatformDependent.directBufferAddress(buffer)方法获取Buffer真是的内存地址,并保存到memoryAddress变量中。PlatformDependent.directBufferAddress(buffer)的实现代码如下:

    public static long directBufferAddress(ByteBuffer buffer) {return PlatformDependent0.directBufferAddress(buffer);}static long directBufferAddress(ByteBuffer buffer) {return getLong(buffer, ADDRESS_FIELD_OFFSET);}private static long getLong(Object object, long fieldOffset) {return UNSAFE.getLong(object, fieldOffset);}

         上述代码最终调用了Unsafe的getLong方法,这是一个native方法。直接通过Buffer的内存地址加上一个偏移量去获取数据。到这里,已经基本清楚了UnpooledUnsafeDirectByteBuf和UnpooledDirectByteBuf的区别,非Unsafe通过数组的下标取数据,Unsafe直接操作内存地址,相对于非Unsafe来说,效率当然更高。

                  


https://www.xjx100.cn/news/3366210.html

相关文章

C++ AVL树(旋转)

我们之前学习了搜索二叉树&#xff0c;我们知道普通的搜索二叉树会有特殊情况出现使得二叉树的两枝极其不平衡形成我们通俗说的歪脖子树&#xff1a; 这样的树一定会使得我们的增删查的效率变低&#xff1b;为了避免这种极端的情况出现&#xff0c;在1962年有两位伟大的俄罗斯数…

Windows搭建Lychee图片管理系统结合内网穿透实现公网访问本地图床

文章目录 1.前言2. Lychee网站搭建2.1. Lychee下载和安装2.2 Lychee网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 图床作为图片集中存放的服务网站&#xff0c;可以看做是云存储的一部分&#xff0c;既可…

zabbix绑定钉钉进行通知,网页端添加JavaScript,无脑式操作

文章目录 前言一、编辑zabbix告警JavaScript脚本二、代码如下:编辑消息模板,自定义markdown格式的消息。总结前言 随着人工智能的不断发展,zabbix监控这门技术也越来越重要,一下进入正题。 一、编辑zabbix告警JavaScript脚本 没有没接可以新增媒介 其中URL是你的机器人地…

基于LSB(最低有效位)的图像水印算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

llama.cpp运行qwen0.5B

编译llama.cp 参考 下载模型 05b模型下载 转化模型 创建虚拟环境 conda create --prefixD:\miniconda3\envs\llamacpp python3.10 conda activate D:\miniconda3\envs\llamacpp安装所需要的包 cd G:\Cpp\llama.cpp-master pip install -r requirements.txt python conver…

软件赋能新型工业化,数智培育新质生产力——第二届软件创新发展大会蓄势待发

我国正在加快培育新质生产力&#xff0c;赋能新型工业化&#xff0c;软件作为新质生产力的基石与引擎&#xff0c;发展机遇空前。武汉是中国软件产业的重要一极&#xff0c;以其独特的地理优势和坚实的产业基础&#xff0c;正逐渐成为国内外瞩目的软件产业集聚发展高地。 武汉发…

从零到一:基于 K3s 快速搭建本地化 kubeflow AI 机器学习平台

背景 Kubeflow 是一种开源的 Kubernetes 原生框架&#xff0c;可用于开发、管理和运行机器学习工作负载&#xff0c;支持诸如 PyTorch、TensorFlow 等众多优秀的机器学习框架&#xff0c;本文介绍如何在 Mac 上搭建本地化的 kubeflow 机器学习平台。 注意&#xff1a;本文以 …

即将截稿 CCF-A多媒体顶会ACM MM‘24 北京时间4月9日提交摘要

会议之眼 快讯 第32届ACM MM (ACM MULTIMEDIA)即国际多媒体会议将于 2024 年 10月28 -日11月1日在澳大利亚墨尔本隆重举行&#xff01;MM是由ACM&#xff08;Association for Computing Machinery&#xff0c;计算机协会&#xff09;主办的国际性学术会议&#xff0c;是计算机…