面试官:说说Netty对象池的实现原理?
Netty 作为一个高性能的网络通讯框架,它内置了很多恰夺天工的设计,目的都是为了将网络通讯的性能做到极致,其中「对象池技术」也是实现这一目标的重要技术。
1.什么是对象池技术?
对象池技术是一种重用对象以减少对象创建和销毁带来的开销的方法。在对象池中,只有第一次访问时会创建对象,并将其维护在内存中,当再次需要使用对象时,会直接从对象池中获取对象,并在使用完毕后归还给对象池,而不是频繁地创建和销毁对象。
使用对象池技术的优点有以下几个:
- 提高性能:复用对象可以减少对象的创建和销毁次数,降低系统开销,提高系统性能和吞吐量。
- 减少内存碎片:对象池可以避免频繁地创建和销毁对象,减少内存碎片的产生,提高内存利用率。
- 避免频繁GC:减少了对象的创建和销毁,可以减少垃圾回收(GC)的频率,降低系统的负担,提高系统的稳定性。
2.对象池基本使用
Netty 对象池技术的核心实现类为 Recycler,Recycler 主要提供了以下 3 个方法:
- get():获取一个可重复使用的对象,如果对象池中有空闲对象,则返回其中一个;否则会创建一个新对象。
- recycle(T, Handle):回收一个对象,将对象放回对象池中以便下次复用。
- newObject(Handle):当对象池中没有可用对象时,此方法会被调用以创建新的对象实例。
接下来我们写一个 Recycler 对象池的使用 Demo,假设我们有一个 User 类,需要实现 User 对象的复用,具体实现代码如下:
public class UserRecyclerDemo {
private static final Recycler<User> userRecycler = new Recycler<User>() {
@Override
protected User newObject(Handle<User> handle) {
return new User(handle);
}
};
static final class User {
private String name;
private Recycler.Handle<User> handle;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public User(Recycler.Handle<User> handle) {
this.handle = handle;
}
public void recycle() {
handle.recycle(this);
}
}
public static void main(String[] args) {
User user1 = userRecycler.get(); // 1.从对象池获取 User 对象
user1.setName("zhangsan"); // 2.设置 User 对象的属性
user1.recycle(); // 3.回收对象到对象池
User user2 = userRecycler.get(); // 4.从对象池获取对象
System.out.println(user1 == user2);
System.out.println(user2.getName());
}
}
以上程序的执行结果如下:
true
zhangsan
从上述结果可以看出,当第一次调用 userRecycler.get() 时,因为对象池中尚未存在 user 对象,所以创建了 name 为“zhangsan”的对象。但第二次再调用 userRecycler.get() 时,因为对象池中已经存在了 user 对象,所以直接从对象池中取出了 user 对象,所以 user1==user2 时,得到的结果是 true。
3.对象池技术应用
在 Netty 中,使用 Recycler 对象池管理对象的常见类有以下几个:
- PooledHeapByteBuf:管理堆内存中的 ByteBuf 对象。
- PooledDirectByteBuf:管理堆外内存中的 ByteBuf 对象。
- ChannelOutboundBuffer.Entry:Netty 出站缓冲区(ChannelOutboundBuffer)中,每一个待发送的消息都包装在一个 Entry 对象中。
4.实现原理
要搞清楚 Netty 对象池技术的实现原理,就要搞清楚 Netty 对象池的核心组件,以及组件之间的关系。
Netty 对象池技术的实现依靠以下 4 大组件:
- Stack(栈):每个线程都关联一个 Stack(使用 FastThreadLocal 进行存储),用于存储和管理该线程回收的对象。Stack 中存储的是 DefaultHandle 对象,这些 DefaultHandle 对象包装了实际要重用的对象。Stack 是与线程绑定的,每个线程从自己的 Stack 中获取对象。
- WeakOrderQueue(弱序队列):当某个线程(非主线程)回收对象时,这些对象不会直接放入主线程的 Stack 中,而是放入 WeakOrderQueue 中。WeakOrderQueue 存储的是从其他线程回收的对象,这些对象被包装在 DefaultHandle 中。WeakOrderQueue 与 Stack 关联,但属于非主线程。当主线程的 Stack 为空时,会尝试从 WeakOrderQueue 中获取对象。
- Link(链表):WeakOrderQueue 中的存储单元,用于存储回收的对象。Link 中存储的是 DefaultHandle 对象数组,这些数组包含从其他线程回收的对象。
- DefaultHandle:对象的包装类,在 Recycler 中缓存的对象都会包装成 DefaultHandle 类。DefaultHandle 中存储了实际要重用的对象,以及与之相关的元数据。
简单来说,这 4 个组件的关系是,(每个)线程为了保证线程安全和高效性操作,所以会把使用的对象放到 Stack 栈中,且每个线程都有自己的 Stack 栈。当线程中的对象不再被使用时(也就是被回收时),并不会将回收对象直接放到 Stack 中(因为当前线程已经不再使用了),此时会将对象存放到 WeakOrderQueue 队列中,因为 WeakOrderQueue 队列相当于“线程共享的区域”,这样其他线程就可以方便的从 WeakOrderQueue 中获取对象进行重用了。而 WeakOrderQueue 中的存储单元是 Link 链表,它存储的是对象池中的包装对象 DefaultHandle,这就是这四大核心组件之间的关系。
5.线程如何获取对象?
在 Netty 中,获取对象池中对象的流程如下:
- 判断 Stack:线程首先会尝试从自己的 Stack 中获取对象。如果 Stack 中有对象,则直接弹出(pop)并返回。
- Stack 为空:如果 Stack 为空,线程会检查 WeakOrderQueue。如果 WeakOrderQueue 中有对象,则按照一定的规则(如“1/7规则”,每 7 个移动 1 个)将部分对象转移到 Stack 中,然后从 Stack 中弹出并返回。
- 创建新对象:如果 Stack 和 WeakOrderQueue 都为空,线程会调用 newObject() 方法创建一个新的对象,并包装成 DefaultHandle 后放入 Stack 中,然后返回该对象。
通过这样的设计,Netty 的 Recycler 对象池技术能够高效地重用对象,减少内存分配和垃圾收集的开销,提升性能。
课后思考
Netty 是如何利用池化技术管理内存的?讲讲它的具体实现?
本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。
面试官:说说Netty对象池的实现原理?的更多相关文章
- 面试官:Netty的线程模型可不只是主从多Reactor这么简单
笔者看来Netty的内核主要包括如下图三个部分: 其各个核心模块主要的职责如下: 内存管理 主要提高高效的内存管理,包含内存分配,内存回收. 网通通道 复制网络通信,例如实现对NIO.OIO等底层JA ...
- Netty源码解析 -- 对象池Recycler实现原理
由于在Java中创建一个实例的消耗不小,很多框架为了提高性能都使用对象池,Netty也不例外. 本文主要分析Netty对象池Recycler的实现原理. 源码分析基于Netty 4.1.52 缓存对象 ...
- 面试官:Netty心跳检测机制是什么,怎么自定义检测间隔时间?
哈喽!大家好,我是小奇,一位热爱分享的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 书接上回,昨天在地里干了一天的 ...
- 笑死,面试官又问我SpringBoot自动配置原理
面试官:好久没见,甚是想念.今天来聊聊SpringBoot的自动配置吧? 候选者:嗯,SpringBoot的自动配置我觉得是SpringBoot很重要的"特性"了.众所周知,Spr ...
- Java对象池技术的原理及其实现
看到一片有关于java 对象基础知识,故转载一下,同时学习一下. 摘 要 本文在分析对象池技术基本原理的基础上,给出了对象池技术的两种实现方式.还指出了使用对象池技术时所应注意的问题. 关键词 对象池 ...
- 面试官:你分析过mybatis工作原理吗?
Mybatis工作原理也是面试的一大考点,必须要对其非常清晰,这样才能怼回去.本文建立在Spring+SpringMVC+Mybatis整合的项目之上. 我将其工作原理分为六个部分: 读取核心配置文件 ...
- 给面试官讲明白:一致性Hash的原理和实践
"一致性hash的设计初衷是解决分布式缓存问题,它不仅能起到hash作用,还可以在服务器宕机时,尽量少地迁移数据.因此被广泛用于状态服务的路由功能" 01分布式系统的路由算法 假设 ...
- Netty轻量级对象池实现分析
什么是对象池技术?对象池应用在哪些地方? 对象池其实就是缓存一些对象从而避免大量创建同一个类型的对象,类似线程池的概念.对象池缓存了一些已经创建好的对象,避免需要时才创建对象,同时限制了实例的个数.池 ...
- netty源码分析 - Recycler 对象池的设计
目录 一.为什么需要对象池 二.使用姿势 2.1 同线程创建回收对象 2.2 异线程创建回收对象 三.数据结构 3.1 物理数据结构图 3.2 逻辑数据结构图(重要) 四.源码分析 4.2.同线程获取 ...
- 抓到 Netty 一个隐藏很深的内存泄露 Bug | 详解 Recycler 对象池的精妙设计与实现
欢迎关注公众号:bin的技术小屋,如果大家在看文章的时候发现图片加载不了,可以到公众号查看原文 本系列Netty源码解析文章基于 4.1.56.Final版本 最近在 Review Netty 代码的 ...
随机推荐
- c# 深克隆与浅克隆
前言 我们都知道memberwiseclone 会将浅克隆. 什么是浅克隆?如何深克隆呢? 正文 public class good{ private good(){ oneclass=new cla ...
- FPGA技术脚本使用
做fpga 不会脚本,基本跟残废一个概念.以前我觉得做FPGA应该学习什么人工智能,大数据,机器人.现在想起来真是傻逼,做fpga也好,做ic,做逻辑其实基本能力都是一样的. 一个学习tcl脚本,pe ...
- git fork 项目的更新
fork:github网站的操作,将开源项目复制一份到自己的仓库中 那fork的项目在原仓库更新后,如何同步呢? 1.查看远程仓库 $ git remote -v origin https://cod ...
- 顺通家用电器生产工厂ERP管理系统
顺通家用电器生产工厂ERP管理系统是一款面向中小制造企业,以智能制造与精益管理为核心的一体化管理软件,符合行业特性的管理流程,与经营特征,形成行业化管理应用软件,为企业提供各方面信息化的管理应用与支持 ...
- .Net与AI的强强联合:AntSK知识库项目中Rerank模型的技术突破与实战应用
随着人工智能技术的飞速发展,.Net技术与AI的结合已经成为了一个新的技术热点.今天,我要和大家分享一个令人兴奋的开源项目--AntSK,这是一个基于.net平台构建的开源离线AI知识库项目.在这个项 ...
- Java集成系列:高效构建自定义插件
前言 随着软件开发的快速发展和需求的不断增长,开发人员面临着更多的压力和挑战.传统的开发方法需要花费大量的时间和精力,而低代码开发平台的出现为开发人员提供了一种更加高效.快速的开发方式.今天小编就以构 ...
- Fluid 给数据弹性一双隐形的翅膀 -- 自定义弹性伸缩
简介: 弹性伸缩作为 Kubernetes 的核心能力之一,但它一直是围绕这无状态的应用负载展开.而 Fluid 提供了分布式缓存的弹性伸缩能力,可以灵活扩充和收缩数据缓存. 它基于 Runtime ...
- 本地已经有项目需要的所有依赖,但是maven总是会去网上下载
情况说明本地已经有项目需要的所有依赖,但是maven总是会去网上下载,因为网络不好等原因,一直下载失败,但是本地明明就已经有依赖了.maven的settings配置 maven已经配置成自己下载的,至 ...
- [FAQ] Fontconfig error: Cannot load default config file
在使用一些第三方库时(比如生成图片),如果出现此提示,说明系统里缺少字体. 在 Ubuntu 上可以运行:$ apt-get install fontconfig 在 Centos 上可以运行:$ ...
- [ML] 数据预处理 - 特性归一化的目的
简而言之,归一化的目的就是使得预处理的数据被限定在一定的范围内(比如[0,1]或者[-1,1]), 从而消除奇异样本数据导致的不良影响. 是否归一化主要在于是否关心变量取值. Tool:ChatAI ...