此文章是研究netty过程中的记录,很有可能有很多不对的地方,欢迎指正

之所以研究netty Recycler,是因为生产环境中遇到了由其引发的堆内存占用率过高的现象。
实验所用源码

回收对象分为两种:同一线程 不同线程。

同一线程

在同一线程中,对象回收至Recycler$Stack中

实验代码

package test.recycler;import io.netty.util.Recycler;
import io.netty.util.concurrent.FastThreadLocalThread;import java.rmi.server.ExportException;
import java.util.ArrayList;
import java.util.List;/*** unreachable Recycler$DefaultHandle*/
public class RecycleNoRelease1 {private static final Recycler<User> RECYCLER = new Recycler<User>() {//没有对象的时候,新建一个对象, 会传入一个handler,在Recycler池里,所有的对象都会转成DefaultHandle对象@Overrideprotected User newObject(Handle<User> handle) {return new User(handle);}};private static ThreadLocal<Long> numLong = new ThreadLocal<Long>();private static class User {private final Recycler.Handle<User> handle;public long a1 = 1;//1kbpublic long a2 = 2;public long a3 = 1;//1kbpublic long a4 = 2;public long a5 = 1;//1kbpublic long a6 = 2;public long a7 = 1;//1kbpublic long a8 = 2;public User(Recycler.Handle<User> handle) {this.handle = handle;}public void recycle() {//通过handler进行对象的回收handle.recycle(this);}}public static void main(String[] args) throws InterruptedException {//        try {//            //此处添加延时是为了让我来得及打开JVisualVM去查看动态变化并使用jmap生成dump文件
//            Thread.sleep(20000);
//        } catch (Exception e) {//            e.printStackTrace();
//        }System.out.println("begin");FastThreadLocalThread thread = new FastThreadLocalThread(new Runnable() {public void run() {long nnn = 1024 * 32;List<User> list1 = new ArrayList<User>();for (int i = 0; i < nnn; ++i) {list1.add(RECYCLER.get());}for (int i = 0; i < nnn; ++i) {list1.get(i).recycle();}}});thread.start();thread.join();System.out.println("=======================over===================================");while (true) {try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}}}
}

通过debug发现,回收对象时会将对象存储至stack中


上面两张图说明线程的ThreadLocal里存储了592这个对象,而本次会回收的对象就是592

并不是每一次调用回收方法的时候对象都能回收到stack中,回收的过程中有一个判断

boolean dropHandle(DefaultHandle<?> handle) {if (!handle.hasBeenRecycled) {if (handleRecycleCount < interval) {handleRecycleCount++;// Drop the object.return true;}handleRecycleCount = 0;handle.hasBeenRecycled = true;}return false;}

如果上面的结果为true,对象必然不会进入stack中。如果为false,上层函数还会进行其他判断。
interval是间隔的意思。当运行RecycleInterval(github中的代码)时可以看到对象周期性的入stack

当线程结束时,592这种对象就会变成unreachable

线上曾经遇到DefaultHandle直接为unreachable,推测可能是jvm将DefaultHandle上一层对象(此例中为RecycleNoRelease1$User)回收了。但是jvm会只回收上一层对象而不回收DefaultHandle吗?这部分还需要做实验。

不同线程

实验代码

package test.recycler;import io.netty.util.Recycler;
import io.netty.util.concurrent.FastThreadLocalThread;import java.util.ArrayList;
import java.util.List;/*** thread用于创建对象,thread2用于回收对象。用于引发WeakOrderQueue$Link的unreachable*/
public class RecycleMultiThread {private static final Recycler<User> RECYCLER = new Recycler<User>() {//没有对象的时候,新建一个对象, 会传入一个handler,在Recycler池里,所有的对象都会转成DefaultHandle对象@Overrideprotected User newObject(Handle<User> handle) {return new User(handle);}};private static Object lock = new Object();private static class User {private final Recycler.Handle<User> handle;public long a1 = 1;//1kbpublic long a2 = 2;public long a3 = 1;//1kbpublic long a4 = 2;public long a5 = 1;//1kbpublic long a6 = 2;public long a7 = 1;//1kbpublic long a8 = 2;public User(Recycler.Handle<User> handle) {this.handle = handle;}public void recycle() {//通过handler进行对象的回收handle.recycle(this);}}public static void main(String[] args) throws InterruptedException {try {//此处添加延时是为了让我来得及打开JVisualVM去查看动态变化并使用jmap生成dump文件Thread.sleep(20000);} catch (Exception e) {e.printStackTrace();}System.out.println("begin");final List<User> list1 = new ArrayList<User>();FastThreadLocalThread thread = new FastThreadLocalThread(new Runnable() {public void run() {long nnn = 1024 * 32;for (int i = 0; i < nnn; ++i) {list1.add(RECYCLER.get());}try {System.out.println("thread lock begin");synchronized (RecycleMultiThread.class) {RecycleMultiThread.class.notify();//对象创建完毕RecycleMultiThread.class.wait();}System.out.println("thread lock over");} catch (Exception e) {e.printStackTrace();}}});FastThreadLocalThread thread2 = new FastThreadLocalThread(new Runnable() {public void run() {long nnn = 1024 * 32;synchronized (RecycleMultiThread.class) {try {RecycleMultiThread.class.wait();//等待对象创建完毕} catch (InterruptedException e) {e.printStackTrace();}}for (int i = 0; i < 1024 * 32; ++i) {list1.get(i).recycle();}try {System.out.println("thread2 notify");synchronized (RecycleMultiThread.class) {RecycleMultiThread.class.notify();}System.out.println("thread2 notify over");} catch (Exception e) {e.printStackTrace();}}});thread.start();thread2.start();thread.join();thread2.join();System.out.println("=======================over===================================");while (true) {try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}}}
}

回收至WeakOrderQueue中


查找上图中@0xffd8aa30的最短路径

为unreachable

此现象与线上系统的dump文件相似(线上dump文件直接就是WeakOrderQueue L i n k u n r e a c h a b l e ) , 据 此 推 测 线 上 老 年 代 出 现 大 量 不 可 达 对 象 的 原 因 就 在 于 线 程 退 出 时 其 T h r e a d L o c a l 依 旧 在 老 年 代 占 有 大 量 空 间 , 并 且 由 于 线 程 已 经 退 出 , 所 以 W e a k O r d e r Q u e u e Link unreachable),据此推测线上老年代出现大量不可达对象的原因就在于线程退出时其ThreadLocal依旧在老年代占有大量空间,并且由于线程已经退出,所以WeakOrderQueue Linkunreachable),据此推测线上老年代出现大量不可达对象的原因就在于线程退出时其ThreadLocal依旧在老年代占有大量空间,并且由于线程已经退出,所以WeakOrderQueueLink直接变成unreachable

netty Recycler(一)相关推荐

  1. netty Recycler对象回收

    netty Recycler对象回收 相关类与接口 Recycler:对象重复使用 public abstract class Recycler<T> {private static fi ...

  2. netty Recycler(二)——WeakOrderQueue和Stack

    之前一直搞不清楚WeakOrderQueue的用途,"将别的线程的对象回收到本线程"还是"将别的线程的对象回收到别的线程"(前者是对的).所以研究了一下 版本一 ...

  3. netty Recycler(三)WeakOrderQueue unreachable

    由于线上问题是由大量的WeakOrderQueue$Link对象引起的,而这些对象都是unreachable,为了研究线上问题的原因,尝试重新构建出WeakOrderQueue$Link的unreac ...

  4. 关于Netty中的Recycler对象池

    1.对象池的背景 Netty本身作为通信用的框架,消息的创建和处理十分频繁,大多数的消息本身可循环使用的程度不高,大部分都是创建完传输后就被等待GC了.但是考虑到大部分消息只是消息部分内容有所差异,可 ...

  5. 抓到Netty一个隐藏很深的内存泄露Bug | 详解Recycler对象池的精妙设计与实现

    本系列Netty源码解析文章基于 4.1.56.Final版本 最近在 Review Netty 代码的时候,不小心用我的肉眼抓到了一个隐藏很深很深的内存泄露 Bug. 于是笔者将这个故事-哦不 -事 ...

  6. 冷知识:netty的Recycler对象池

    在netty中Recycler用来实现对象池,以达到对象的循环利用,它是netty实现的一个轻量级对象回收站,具体的实现有:堆内存对应PooledHeapByteBuf,而直接内存对应的是Pooled ...

  7. netty集成ssl完整参考指南(含完整源码)

    虽然我们在内部rpc通信中使用的是基于认证和报文头加密的方式实现安全性,但是有些时候仍然需要使用SSL加密,可能是因为对接的三方系统需要,也可能是由于open的考虑.中午特地测了下netty下集成ss ...

  8. netty权威指南学习笔记三——TCP粘包/拆包之粘包现象

    TCP是个流协议,流没有一定界限.TCP底层不了解业务,他会根据TCP缓冲区的实际情况进行包划分,在业务上,一个业务完整的包,可能会被TCP底层拆分为多个包进行发送,也可能多个小包组合成一个大的数据包 ...

  9. Java基础之《netty(28)—TCP粘包拆包原理》

    一.基本介绍 1.TCP是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用了优化方法(Na ...

最新文章

  1. 【Web API系列教程】1.2 — Web API 2中的Action Results
  2. “机器学习还是很难用!”
  3. 产生任意区间内的均匀分布的随机整数序列
  4. DK云网关与普通DTU之间的区别
  5. CreateDirectory GetCurrentDirectory 和SetCurrentDirectory
  6. XCTF-Reverse:simple-unpack
  7. C++虚继承(三) --- C++ 对象的内存布局(下)(陈皓)
  8. 2021 程序媛跳槽记:学习计划篇(已收获字节等offer)
  9. 用于数据分析的Python – Pandas
  10. 2018.01.25-现货黄金复盘
  11. 学习产品型是否要满足人们的“懒”需求
  12. Starling自适应设备大小的做法
  13. CentOS操作系统的22个log日志
  14. 基于matlab的双闭环直流调速系统,基于Matlab双闭环直流调速系统设计与仿真
  15. Mac录制屏幕转GIF
  16. 大学计算机课程日记,大学计算机实习日记.docx
  17. Lab1 Packet Sniffing and Spoofing Lab
  18. js 设置视频的音量大小
  19. 公司企业小程序怎么开发自己的小程序
  20. GLES2.0中文API-glBlendFuncSeparate

热门文章

  1. 知识图谱neo4j安装与启动,并导入食品抽检数据
  2. 祝我们的祖国73周岁快乐!
  3. IE浏览器不能访问其他浏览器能正常访问
  4. union all的效率问题
  5. c语言按键模式切换,二、Windows按键消息—键的先前状态、转换状态、位移状态...
  6. [ 笔记 ] 计算机网络安全_2_internet协议的安全性
  7. windows系统操作快捷键
  8. Mysql上下级结构表设计-冗余所有上下级
  9. arcgis select by attributes一次选多个_ArcGIS中属性表的常用操作汇总
  10. 拉勾网基于 UK8S 平台的容器化改造实践