netty之ResourceLeakDetector的使用与实现

通过WeakReference和ReferenceQueue做针对需要手动释放的资源的侦测

使用

  1. 设置日志级别:
ServerBootstrap b =new ServerBootstrap();
b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 2048)
.handler(new LoggingHandler(LogLevel.DEBUG))
.childHandler(new ChildChannelHandler()); 2017-01-19 10:04:49 [ nioEventLoopGroup-1-0:1628830 ] - [ ERROR ] LEAK: ByteBuf.release() was not called before it's garbage-coll...
  1. ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);或者通过JVM参数配置

    日志:
2017-01-19 10:35:59  [ nioEventLoopGroup-1-0:665092 ] - [ ERROR ]  LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records: 5
#5:
io.netty.buffer.AdvancedLeakAwareByteBuf.readBytes(AdvancedLeakAwareByteBuf.java:435)

分析

[ ERROR ] LEAK:

// ResourceLeakDetector
protected void reportTracedLeak(String resourceType, String records) {
logger.error(
"LEAK: {}.release() was not called before it's garbage-collected. " +
"See http://netty.io/wiki/reference-counted-objects.html for more information.{}",
resourceType, records);
} private void reportLeak() {
if (!logger.isErrorEnabled()) {
clearRefQueue();
return;
} // Detect and report previous leaks.
for (;;) {
@SuppressWarnings("unchecked")
DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll(); // 为什么能拿到?什么时候 放进去的?是weakreference回收过程中放进去的,相当于GC过程让你插入hook。那为什么被GC了还有资源泄露呢?这个问题其实是这样的,泄露是池化内存等那些需要手动释放资源。
if (ref == null) {
break;
} if (!ref.dispose()) { // return allLeaks.remove(this); 所以当有人显式释放过,那么此处就返回false 就不会往下走report了
continue;
} String records = ref.toString();
if (reportedLeaks.putIfAbsent(records, Boolean.TRUE) == null) {
if (records.isEmpty()) {
reportUntracedLeak(resourceType);
} else {
reportTracedLeak(resourceType, records);
}
}
}
}

基本实现原理是:

  1. 通过DefaultResourceLeak继承自WeakReference,借助WeakReference的GC特性完成。WeakReference的GC特性是当这个对象没有被其他强引用对象引用时,仅仅被WeakReference引用(或者其他weak引用)时,会在下一次GC时回收,回收过程中会将被回收的引用放到ReferenceQueue中。此处的ReferenceQueue又是在创建DefaultResourceLeak时通过构造参数传入的。
  2. 不时poll那个ReferenceQueue队列,当拿到对象时看起dispose是否被调用过,如果没有则证明没有显示释放,则report出来。
  3. 每次创建池化buf对象时,便会创建DefaultResourceLeak,并在touch等API中调用其record方法,追踪其申请使用的地方。在开启了泄露追踪后,buf会被包装,比如包装成AdvancedLeakAwareByteBuf。
  4. 侦测reportLeak不是每次都调用,当小雨PARANOID级别是在申请buf时按随机数比例调。PARANOID级别是全调。

此处资源泄露,是指那种需要手动释放的资源,因为引用他的对象已经不在程序逻辑中使用了,那么最终会被GC回收,但是那种需要手动释放的资源不显式释放就泄露了。比如内存池,比方说里面有5个杯子,你用的buf指向一个杯子被你占着,你不用时没显式告诉内存池说这个杯子不用了,那么就一直占着,但是buf对象不用了会被GC回收,那么此时内存池资源就泄露了。

最新文章

  1. PHP 删除文件(图片)
  2. JS_Ajax基础
  3. 谷歌 analytics.js 部分解密版
  4. Java学习笔记——字符串常用函数
  5. 基于JQuery实现相同内容合并单元格[转]
  6. mysql 配置参数
  7. Android KeyCode
  8. ubuntu16.04下安装chrome
  9. Cocoa触发方法调用的几种方法
  10. 如何修改Tomcat默认端口?
  11. 利用Navicat高效率postgresql转mysql数据库
  12. Chapter 4 Invitations——12
  13. <Dare To Dream> 第四次作业:基于原型的团队项目需求调研与分析
  14. 大数据学习笔记4 - Hadoop的优化与发展(Hadoop 2.0)
  15. redis各类错误可能的解决方案
  16. org.apache.maven.archiver.mavenarchiver.getmanifest怎么解决
  17. dos下编译java
  18. STS的安装与简单使用
  19. 【Ubuntu】xrdp完美实现Windows远程访问Ubuntu 16.04
  20. php中的错误和异常

热门文章

  1. 高效C++:定制new和delete
  2. python 简单粗暴的生产的验证码
  3. WebApiClientCore简约调用百度AI接口
  4. 前端css 同级元素 设置不同样式 :first-child :nth-child() 的操作收藏
  5. expect使用技巧
  6. PHP 中的字符串变量
  7. PHP curl_unescape函数
  8. 一本通 高手训练 1788 爬山 dp 斜率 凸包
  9. CF R 632 div2 1333F Kate and imperfection
  10. python6.4项目:股票提醒系统