[Netty源码] Netty轻量级对象池实现分析 (十三)

这篇具有很好参考价值的文章主要介绍了[Netty源码] Netty轻量级对象池实现分析 (十三)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.对象池技术介绍

对象池其实就是缓存一些对象从而避免大量创建同一个类型的对象, 类似线程池。对象池缓存了一些已经创建好的对象, 避免需要的时候创建。同时限制了实例的个数。

池化技术最终要的就是重复的使用池内已经创建的对象。

  • 创建对象的开销大
  • 会创建大量的实例
  • 限制一些资源的使用

如果创建一个对象的开销特别大, 那么需要提前创建一些可以使用的并缓存起来, 池化技术就是重复使用对象, 提前创建并缓存起来重复使用就是池化, 可以降低创建对象的开销。

会大量创建实例的场景, 重复的使用对象可以减少创建的对象数量, 降低GC的压力。

对于限制资源的使用更多的是一种保护机制, 比如数据库连接池, 除去创建对象本身的开销, 们对外部系统也会造成压力, 比如大量创建链接对DB也是有压力的。那么池化除了可以优化资源外, 本身限制了资源数, 对外部系统也起到了一层保护作用。

2.如何实现对象池

Apache Commons Pool, Netty轻量级对象池的实现。

Apache Commons Pool开源软件库提供了一个对象池API和一系列对象池的实现, 支持各种配置, 比如活跃对象数或者闲置对象个数等。DBCP数据库连接池基于Apache Commons Pool实现。

Netty自己实现了一套轻量级的对象池, 在多个IO线程独立工作时候, 基于NioEventLoop的实现, 每个IO线程轮询单独的Selector实例来检索IO事件, 在IO来临时候开始处理。最常见的IO操作就是读写, 具体到NIO就是从内核缓冲区拷贝数据到用户缓冲区或者从用户缓冲区拷贝数据到内核缓冲区。

3.Netty对象池实现分析

NIO提供了两种Buffer最为缓冲区: DirectByteBuffer和HeapByteBuffer, Netty进行了池化提供性能。

Netty的池化分别为PooledDirectByteBuf 和PolledHeapByteBuf。

static PooledDirectByteBuf newInstance(int maxCapacity) {
        PooledDirectByteBuf buf = RECYCLER.get();
        buf.reuse(maxCapacity);
        return buf;
    }

可见RECYCLER是池化的核心, 通过RECYCLER.get获取一个实例。

Recycler就是Netty实轻量级池化技术的核心。

public class RecycleTest {
    private static final Recycler<User> RECYCLER = new Recycler<User>(){
        @Override
        protected User newObject(Handle<User> handle) {
            return new User(handle);
        }
    };

    public static class User{
        private final Recycler.Handle<User> handle;

        public User(Recycler.Handle<User> handle){
            this.handle = handle;
        }

        public void recycle(){
            handle.recycle(this);
        }
    }

    public static void main(String[] args) {
        // 1.获取当前线程的stack
        // 2.从stack中弹出对象
        // 3.创建对象并绑定到stack
        User user = RECYCLER.get();
        user.recycle();
        User user1 = RECYCLER.get();
        System.out.println(user == user1);
    }
}
true
3.1 Recycler

整个对象池的核心实现由ThreadLocal, Handler和Stack及WrakOrderQueue构成。

[Netty源码] Netty轻量级对象池实现分析 (十三)

[Netty源码] Netty轻量级对象池实现分析 (十三)

  1. Stack相当于是一级缓存,同一个线程内的使用和回收都将使用一个Stack
  2. 每个线程都会有一个自己对应的Stack,如果回收的线程不是Stack的线程,将元素放入到Queue中
  3. 所有的Queue组合成一个链表,Stack可以从这些链表中回收元素(实现了多线程之间共享回收的实例)

[Netty源码] Netty轻量级对象池实现分析 (十三)

  • get(): 获取对象
    public final T get() {
        if (maxCapacityPerThread == 0) {
            return newObject((Handle<T>) NOOP_HANDLE);
        }
        Stack<T> stack = threadLocal.get();
        DefaultHandle<T> handle = stack.pop();
        if (handle == null) {
            handle = stack.newHandle();
            handle.value = newObject(handle);
        }
        return (T) handle.value;
    }
  • 拿到当前线程对应的stack
  • 从stack中pop出一个元素
  • 如果不为空则返回,否则创建一个新的实例
    public final boolean recycle(T o, Handle<T> handle) {
        if (handle == NOOP_HANDLE) {
            return false;
        }

        DefaultHandle<T> h = (DefaultHandle<T>) handle;
        if (h.stack.parent != this) {
            return false;
        }

        h.recycle(o);
        return true;
    }
  • Recycler的recycle方法主要做了一些参数验证。
3.2 Handler

recycle(): 放回池子中的方法, Recycler的recycle方法和DefaultHandle的recycle方法。

        @Override
        public void recycle(Object object) {
            if (object != value) {
                throw new IllegalArgumentException("object does not belong to handle");
            }

            Stack<?> stack = this.stack;
            if (lastRecycledId != recycleId || stack == null) {
                throw new IllegalStateException("recycled already");
            }

            stack.push(this);
        }
  • Recycler的recycle方法主要做了一些参数验证。
  • DefaultHandle的recycle方法:
    1. 如果当前线程是当前stack对象的线程, 放入stack。
    2. 获取当前线程对应的Map<Stack, WeakOrderQueue>, 实例放入stack对应的queue中。
3.3 Stack

Stack是对象池化背后存储实例的数据结构, 如果能从stack中拿到可用的实例就不再创建新的实例。

        final Recycler<T> parent;
        final WeakReference<Thread> threadRef;
        final AtomicInteger availableSharedCapacity;
        final int maxDelayedQueues;

        private final int maxCapacity;
        private final int ratioMask;
        private DefaultHandle<?>[] elements;
        private int size;
        private int handleRecycleCount = -1; // Start with -1 so the first one will be recycled.
        private WeakOrderQueue cursor, prev;
        private volatile WeakOrderQueue head;

[Netty源码] Netty轻量级对象池实现分析 (十三)

pop()

        DefaultHandle<T> pop() {
            int size = this.size;
            // 如过size = 0, scavenge
            if (size == 0) {
                if (!scavenge()) {
                    return null;
                }
                size = this.size;
            }
            size --;
            DefaultHandle ret = elements[size];
            elements[size] = null;
            if (ret.lastRecycledId != ret.recycleId) {
                throw new IllegalStateException("recycled multiple times");
            }
            ret.recycleId = 0;
            ret.lastRecycledId = 0;
            this.size = size;
            // 返回elements最后一个元素
            return ret;
        }

push(): 同线程和异步线程回收对象

[Netty源码] Netty轻量级对象池实现分析 (十三)

同步线程回收对象

        private void pushNow(DefaultHandle<?> item) {
            if ((item.recycleId | item.lastRecycledId) != 0) {
                throw new IllegalStateException("recycled already");
            }
            item.recycleId = item.lastRecycledId = OWN_THREAD_ID;

            int size = this.size;
            if (size >= maxCapacity || dropHandle(item)) {
                return;
            }
            if (size == elements.length) {
                elements = Arrays.copyOf(elements, min(size << 1, maxCapacity));
            }

            elements[size] = item;
            this.size = size + 1;
        }

异步线程回收对象

  1. 获取WeakOrderQueue
  2. 创建WeakOrderQueue
  3. 将对象追加到WeakOrderQueue
        private void pushLater(DefaultHandle<?> item, Thread thread) {
			// 获取WeakOrderQueue
            Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();
            WeakOrderQueue queue = delayedRecycled.get(this);
            if (queue == null) {
                if (delayedRecycled.size() >= maxDelayedQueues) {
                    delayedRecycled.put(this, WeakOrderQueue.DUMMY);
                    return;
                }
                // 创建WeakOrderQueue
                if ((queue = WeakOrderQueue.allocate(this, thread)) == null) {
                    // drop object
                    return;
                }
                delayedRecycled.put(this, queue);
            } else if (queue == WeakOrderQueue.DUMMY) {
                // drop object
                return;
            }
			// 将对象追加到WeakOrderQueue
            queue.add(item);
        }

[Netty源码] Netty轻量级对象池实现分析 (十三)

queue是一个队列形式, 节点为Link, Link中是Handler (处理逻辑)

3.4 WeakOrderQueue
  head,tail:Link                       // 内部元素的指针(WeakOrderQueue内部存储的是一个Link的链表)
  next:WeakOrderQueue     // 指向下一个WeakOrderQueue的指针
  owner:Thread                      // 对应的线程

[Netty源码] Netty轻量级对象池实现分析 (十三)

WeakOrderQueue的结构图

[Netty源码] Netty轻量级对象池实现分析 (十三)

WeakOrderQueue中是一个一个Link组成

[Netty源码] Netty轻量级对象池实现分析 (十三)

add方法将元素添加到自身的“队列”中, transfer方法将自己拥有的元素“传输”到Stack中。

        void add(DefaultHandle<?> handle) {
            handle.lastRecycledId = id;

            Link tail = this.tail;
            int writeIndex;
            if ((writeIndex = tail.get()) == LINK_CAPACITY) {
                if (!head.reserveSpace(LINK_CAPACITY)) {
                    // Drop it.
                    return;
                }
                // We allocate a Link so reserve the space
                this.tail = tail = tail.next = new Link();

                writeIndex = tail.get();
            }
            tail.elements[writeIndex] = handle;
            handle.stack = null;
            // we lazy set to ensure that setting stack to null appears before we unnull it in the owning thread;
            // this also means we guarantee visibility of an element in the queue if we see the index updated
            tail.lazySet(writeIndex + 1);
        }

add操作将元素添加到tail指向的Link对象中,如果Link已满则创建一个新的Link实例。

3.5 Link
        static final class Link extends AtomicInteger {
        	// 处理逻辑Handler
            private final DefaultHandle<?>[] elements = new DefaultHandle[LINK_CAPACITY];
			// 读的指针
            private int readIndex;
            Link next;
        }

Link内部包含了一个数组用于存放实例, 同时标记了读取位置的索引和下一个Link元素的指针。

[Netty源码] Netty轻量级对象池实现分析 (十三)

4.总结

Recyler -> Stack-> WeakOrderQueue -> Link -> Handler

[Netty源码] Netty轻量级对象池实现分析 (十三)文章来源地址https://www.toymoban.com/news/detail-417093.html

到了这里,关于[Netty源码] Netty轻量级对象池实现分析 (十三)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于yolov5轻量级的学生上课姿势检测识别分析系统

    在我之前的博文中已经做过关于人体姿势识别人体姿态检测的博文,都是比较早期的技术模型了,随机技术的迭代更新,很多更加出色的模型陆续出现,这里基于一些比较好用的轻量级模型开发的姿态检测模型。 原始博文如下: 《人体行为姿势识别数据集WISDM实践》   《y

    2024年01月17日
    浏览(34)
  • 一种轻量级定时任务实现

    现在市面上有各式各样的分布式定时任务,每个都有其独特的特点,我们这边的项目因为一开始使用的是分布式开源调度框架TBSchedule,但是这个框架依赖ZK, 由于ZK的不稳定性和项目老旧无人维护 ,导致我们的定时任务会偶发出现异常,比如:任务停止、任务项丢失、任务不

    2024年02月14日
    浏览(27)
  • 一种轻量级websocket实现方案

    定义ws服务器工具类WsktUtil 开机启动ws服务器 测试结果 自定义一个WebSocketClient子类 测试连接ws服务器 测试效果

    2024年02月15日
    浏览(29)
  • 轻量级狂雨小说cms系统源码 v1.5.2 基于ThinkPHP5.1+MySQL

    轻量级狂雨小说cms系统源码 v1.5.2 基于ThinkPHP5.1+MySQL的技术开发 狂雨小说cms提供一个轻量级小说网站解决方案,基于ThinkPHP5.1+MySQL的技术开发。 KYXSCMS,灵活,方便,人性化设计简单易用是最大的特色,是快速架设小说类网站首选,只需5分钟即可建立一个海量小说的行业网站,

    2024年02月07日
    浏览(30)
  • 使用es实现轻量级分布式锁

    一般来说,实现分布式锁的方式有哪几种? 一:Redisson实现 二:ZK实现   这两种实现网上的实现是千篇一律,在本文就不做过多的讲解了   其它方式好像没有了,真的是这样么?   答案是否定的,今天我就给大家分享一个新的思路,使用es实现一个分布式锁,分布式

    2024年02月06日
    浏览(46)
  • 轻量级软件FastGithub实现稳定访问github

    当我们想访问全球最大的“同性交友网站”https://github.com/ 时,总会出现无法访问的界面,令人非常苦恼: 幸运的是,有一种轻量级的软件可以帮助我们稳定地访问GitHub,那就是FastGithub。 FastGithub是一个简洁且专一的软件,它可以帮助你稳定地访问GitHub。FastGithub通过修改本地

    2024年02月06日
    浏览(38)
  • Spring Boot整合Postgres实现轻量级全文搜索

    有这样一个带有搜索功能的用户界面需求: 搜索流程如下所示: 这个需求涉及两个实体: “评分(Rating)、用户名(Username)”数据与 User 实体相关 “创建日期(create date)、观看次数(number of views)、标题(title)、正文(body)”与 Story 实体相关 需要支持的功能对 User

    2024年02月19日
    浏览(29)
  • 教你使用PHP实现一个轻量级HTML模板引擎

    🏆作者简介,黑夜开发者,全栈领域新星创作者✌,2023年6月csdn上海赛道top4。多年电商行业从业经验,对系统架构,数据分析处理等大规模应用场景有丰富经验。 🏆本文已收录于PHP专栏:PHP进阶实战教程。 🏆另有专栏PHP入门基础教程,希望各位大佬多多支持❤️。 在 W

    2024年02月15日
    浏览(29)
  • OpenHarmony实战开发-如何实现一个轻量级输入法应用。

    ​ 本示例使用inputMethodEngine实现一个轻量级输入法应用kikaInput,支持在运行OpenHarmony OS的智能终端上。 使用说明 1.使用hdc shell aa start ability -a InputMethod -b cn.openharmony.inputmethodchoosedialog命令拉起切换输入法弹窗,点击kikainput切换输入法到当前应用。 2.点击应用中的编辑框,拉起

    2024年04月24日
    浏览(38)
  • Android:Linux上编译OpenCV的Android库,从源码编译出一个轻量级的OpenCV安卓库

    (原文在这里,我根据这篇文章终于也能编译成功可以使用的OpenCV库文件了: Linux上编译OpenCV的Android库 https://zhuanlan.zhihu.com/p/301203711 整个编译过程只用下载Android NDK和OpenCV源码。工具链android.toolchain.cmake,是NDK:android-ndk-r19c-linux-x86_64自带的,不用自己编译了。使用WSL Ubuntu记

    2024年02月05日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包