• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
中间件爱好者
博客园    首页    新随笔    联系   管理    订阅  订阅
直接内存/Netty中的ByteBuf

直接内存(DirectByteBuffer)

1.为什么使用直接内存:

​ 当进行网络 I/O 操作、文件读写时,堆内内存都需要转换为堆外内存,然后再与底层设备进行交互,所以直接使用堆外内存可以减少一次内存拷贝。

2.如何使用直接内存:

​ 在nio中,通过创建DirectByteBuffer对象(ByteBuffer.allocateDirect())来完成,在创建DirectByteBuffer时,内部

使用unsafe.allocateDirect来分配直接内存.DirectByteBuffer中的memory指向这块内存。

3.直接内存如何回收:(依赖GC)

​ 在gc时,DirectByteBuffer如果被回收,那么与之关联的直接内存也会被回收。原理:在构建DirectByteBuffer时,

会构建一个Cleaner,这个Cleaner是一个虚引用; 当DirectByteBuffer被gc之后,这个对应的虚应用会被加入到pending列表(具体代码看jdk的Reference类),然后判断当前应用是否是Cleaner,是的话执行 clean() 方法。在clean() 方法中,会调用 unsafe.freeMemory 方法清理堆外内存。

4.直接内存默认大小和-Xmx指定的最大堆大小一样大 -XX:+MaxDirectMemorySize。

注意:DirectByteBuffer对象可能长时间得不到回收,那么分配的直接内存即使不用了,也无法回收掉。为了防止物理内存耗尽,

需要设置-XX:+MaxDirectMemorySize

Netty中的ByteBuf

Netty中的ByteBuf相较于jdk中的ByteBuffer具有如下优势

1.ByteBuf提供读写指针。在操作数据时不需要进行flip操作

2.支持基于引用计数器的回收策略。不像ByteBuffer那么死板,需要gc才能回收。

3.提供池化操作,不用频繁分配内存。

4.容量可以按需进行扩容

5.Netty提供了池化/非池化,直接/堆,unsafe/非unsafe等组合类型的ByteBuf

引用计数

通过引用计数,可以快速释放内存。ByteBuf都实现了AbstractReferenceCountedByteBuf,当使用完之后,手动调用release方法。

  @Override
    public boolean release(int decrement) {
        return handleRelease(updater.release(this, decrement));
    }

    private boolean handleRelease(boolean result) {
        if (result) {
            deallocate();
        }
        return result;
    }

    /**
     * Called once {@link #refCnt()} is equals 0.
     */
    protected abstract void deallocate();

1.用非池化的直接内存:UnpooledDirectByteBuf举例。通过调用release方法,就可以将直接内存释放掉。相较于DirectByteBuffer来说

是一个大的优势。

   @Override
    protected void deallocate() {
        ByteBuffer buffer = this.buffer;
        if (buffer == null) {
            return;
        }
			
        this.buffer = null;
				//释放直接内存。
        if (!doNotFree) {
            freeDirect(buffer);
        }
    }

2.对于池化的B引用计数对于 Netty 设计缓存池化有非常大的帮助,当引用计数为 0,该 ByteBuf 可以被放入到对象池中,避免每次使用 ByteBuf 都重复创建,对于实现高性能的内存管理有着很大的意义。

此外 Netty 可以利用引用计数的特点实现内存泄漏检测工具。JVM 并不知道 Netty 的引用计数是如何实现的,当 ByteBuf 对象不可达时,一样会被 GC 回收掉,但是如果此时 ByteBuf 的引用计数不为 0,那么该对象就不会释放或者被放入对象池,从而发生了内存泄漏

posted on 2021-10-19 22:17  中间件爱好者  阅读(364)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3