`

netty内存检测

阅读更多

 1,内存泄露级别

DISABLED, SIMPLE, ADVANCED, PARANOID;

DISABLED(禁用);: 不进行内存泄露的检测;

SIMPLE(操作简单): 抽样检测,且只对部分方法调用进行记录,消耗较小,有泄漏时可能会延迟报告,默认级别;

ADVANCED(高级): 抽样检测,记录对象最近几次的调用记录,有泄漏时可能会延迟报告;

PARANOID(偏执): 每次创建一个对象时都进行泄露检测,且会记录对象最近的详细调用记录。是比较激进的内存泄露检测级别,消耗最大,建议只在测试时使用。

如果需要修改默认的检测级别,可以通过:1、调用静态方法setLevel进行修改;2、设置启动参数io.netty.leakDetectionLevel

 

 

 

netty5学习笔记-内存泄露检测

标签: netty内存泄露检测
 43人阅读 评论(0) 收藏 举报
 分类:
netty学习(6) 

        netty中用到内存泄露检测的地方主要有:1、CompositeByteBuf;2、HashedWheelTimer;3、继承AbstractByteBufAllocator的几个类。

下面我们看看netty里的内存检测类ResourceLeakDetector的具体实现:

 

netty的内存泄露检测分为四级:

DISABLED: 不进行内存泄露的检测;

SIMPLE: 抽样检测,且只对部分方法调用进行记录,消耗较小,有泄漏时可能会延迟报告,默认级别;

ADVANCED: 抽样检测,记录对象最近几次的调用记录,有泄漏时可能会延迟报告;

PARANOID: 每次创建一个对象时都进行泄露检测,且会记录对象最近的详细调用记录。是比较激进的内存泄露检测级别,消耗最大,建议只在测试时使用。

如果需要修改默认的检测级别,可以通过:1、调用静态方法setLevel进行修改;2、设置启动参数io.netty.leakDetectionLevel。

由于内存泄露主要是对某一类资源的检测,因此对于同一类的对象,只需实例化一个ResourceLeakDetector, 否则起不到检测的作用。

 

[java] view plaincopy
 
  1. public class HashedWheelTimer implements Timer {  
  2.     ...  
  3.     private static final ResourceLeakDetector<HashedWheelTimer> leakDetector =  
  4.             new ResourceLeakDetector<HashedWheelTimer>(  
  5.                     HashedWheelTimer.class1, Runtime.getRuntime().availableProcessors() * 4);  
  6.     ...  
初始化的时候需要设置被检测的类(或其他文字标记)、抽样间隔、最大活跃对象数

 

 

[java] view plaincopy
 
  1. public ResourceLeakDetector(String resourceType, int samplingInterval, long maxActive) {  
  2.         if (resourceType == null) {  
  3.             throw new NullPointerException("resourceType");  
  4.         }  
  5.         if (samplingInterval <= 0) {  
  6.             throw new IllegalArgumentException("samplingInterval: " + samplingInterval + " (expected: 1+)");  
  7.         }  
  8.         if (maxActive <= 0) {  
  9.             throw new IllegalArgumentException("maxActive: " + maxActive + " (expected: 1+)");  
  10.         }  
  11.   
  12.         this.resourceType = resourceType;  
  13.         // 抽样间隔,当基本为SIMPLE或ADVANCED时,每创建samplingInterval个对象进行一次记录。  
  14.         this.samplingInterval = samplingInterval;  
  15.         // 最大活跃对象数,超过这个值就会进行对应处理(如报警或主动关闭资源)  
  16.         this.maxActive = maxActive;  
  17.   
  18.         head.next = tail;  
  19.         tail.prev = head;  
  20.     }  
 每次对象创建的时候都需要调用open方法:

 

 

[java] view plaincopy
 
  1. public ResourceLeak open(T obj) {  
  2.         Level level = ResourceLeakDetector.level;  
  3.     // 关闭检测  
  4.         if (level == Level.DISABLED) {  
  5.             return null;  
  6.         }  
  7.   
  8.         if (level.ordinal() < Level.PARANOID.ordinal()) {  
  9.             // 小于PARANOID及ADVANCED和SIMPLE, 每创建samplingInterval个对象调用一次reportLeak  
  10.         if (leakCheckCnt ++ % samplingInterval == 0) {  
  11.                 reportLeak(level);  
  12.                 return new DefaultResourceLeak(obj);  
  13.             } else {  
  14.                 return null;  
  15.             }  
  16.         } else {  
  17.         // PARANOID级别每次都调用reportLeak  
  18.             reportLeak(level);  
  19.             return new DefaultResourceLeak(obj);  
  20.         }  
  21.     }  
  22.     <pre name="code" class="java">private void reportLeak(Level level) {  
  23.     // 内存泄露的主要报告方式为日志,因此如果日志级别不够,则只进行数据处理,不走具体的报告分支  
  24.         if (!logger.isErrorEnabled()) {  
  25.             for (;;) {  
  26.     // 这个refQueue里面主要是被垃圾回收的对象,垃圾回收过的对象如果保存到refQueue不是本次讨论的重点,有兴趣可以搜索PhantomReference,ReferenceQueue相关文章  
  27.                 @SuppressWarnings("unchecked")  
  28.                 DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll();  
  29.                 if (ref == null) {  
  30.                     break;  
  31.                 }  
  32.     // 对回收的对象调用close方法,这个方法会减少active的记数  
  33.                 ref.close();  
  34.             }  
  35.             return;  
  36.         }  
  37.   
  38.   
  39.         // 非PARANOID级别每隔sampleInterval记录一次,因此这里又乘以sampleInterval,使抽样的情况下偏差尽可能小  
  40.             int samplingInterval = level == Level.PARANOID? 1 : this.samplingInterval;  
  41.         if (active * samplingInterval > maxActive && loggedTooManyActive.compareAndSet(falsetrue)) {  
  42.     // 活跃数大于maxActive则进行报警,且只报一次  
  43.             logger.error("LEAK: You are creating too many " + resourceType + " instances.  " +  
  44.                     resourceType + " is a shared resource that must be reused across the JVM," +  
  45.                     "so that only a few instances are created.");  
  46.         }  
  47.   
  48.   
  49.         // Detect and report previous leaks.  
  50.         for (;;) {  
  51.             @SuppressWarnings("unchecked")  
  52.             DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll();  
  53.             if (ref == null) {  
  54.                 break;  
  55.             }  
  56.   
  57.   
  58.             ref.clear();  
  59.   
  60. // 调用close方法,确保该资源被移除,如果返回true,表明资源虽然被垃圾回收掉了,但是没有在应用中显式的调用close方法,后面会在日志中警告用户通过更高的基本来进行更详细的分析  
  61.             if (!ref.close()) {  
  62.                 continue;  
  63.             }  
  64.   
  65.   
  66.             String records = ref.toString();  
  67.             if (reportedLeaks.putIfAbsent(records, Boolean.TRUE) == null) {  
  68.                 if (records.isEmpty()) {  
  69.                     logger.error("LEAK: {}.release() was not called before it's garbage-collected. " +  
  70.                             "Enable advanced leak reporting to find out where the leak occurred. " +  
  71.                             "To enable advanced leak reporting, " +  
  72.                             "specify the JVM option '-D{}={}' or call {}.setLevel() " +  
  73.                             "See http://netty.io/wiki/reference-counted-objects.html for more information.",  
  74.                             resourceType, PROP_LEVEL, Level.ADVANCED.name().toLowerCase(), simpleClassName(this));  
  75.                 } else {  
  76.                     logger.error(  
  77.                             "LEAK: {}.release() was not called before it's garbage-collected. " +  
  78.                             "See http://netty.io/wiki/reference-counted-objects.html for more information.{}",  
  79.                             resourceType, records);  
  80.                 }  
  81.             }  
  82.         }  
  83.     }  
open方法调用后会返回一个ResourceLeak对象,应用可以通过该对象的record方法记录调用详情,同时通过close方法通知资源的释放。
[java] view plaincopy
 
  1. private void record0(Object hint, int recordsToSkip) {  
  2.             if (creationRecord != null) {  
  3.             // 得到当前的调用栈信息,由于这里的执行比较耗时,所以频繁调用对应用是有明显的性能损耗的,因此netty中的默认级别是SIMPLE  
  4.                 String value = newRecord(hint, recordsToSkip);  
  5.                 // 将信息记录到lastRecords中,并保持最多MAX_RECORDS条记录,该信息会在检测到内存泄露时打印到日志中  
  6.                 synchronized (lastRecords) {  
  7.                     int size = lastRecords.size();  
  8.                     if (size == 0 || !lastRecords.getLast().equals(value)) {  
  9.                         lastRecords.add(value);  
  10.                     }  
  11.                     if (size > MAX_RECORDS) {  
  12.                         lastRecords.removeFirst();  
  13.                     }  
  14.                 }  
  15.             }  
  16.         }  
  17.     public boolean close() {  
  18.           // 保证一个对象只执行一次close方法  
  19.             if (freed.compareAndSet(falsetrue)) {  
  20.                 synchronized (head) {  
  21.                     active --;  
  22.                     prev.next = next;  
  23.                     next.prev = prev;  
  24.                     prev = null;  
  25.                     next = null;  
  26.                 }  
  27.                 return true;  
  28.             }  
  29.             return false;  
  30.         }  

内存相关泄露的检测实现本身比较简单,即打开资源时增加一个活跃对象数,释放一次资源时减少一个活跃对象数,如果活跃对象数超过阈值则报告异常。但需要注意的是如果要做到有意义的内存检测则需要遵循新建对象调用ResourceLeakDetector.open方法,释放对象调用ResourceLeak.close,否则可能会出现误报的情况。同时激进的内存检测对性能有很大影响,在生产环境下尽量不要打开。

好了,ResourceLeakDetector的分析到这里基本上结束了,但是还存在几个问题,leakCheckCnt、active、head、tail的操作都是线程不安全的,而netty使用到该类的时候,都是一个类new一个detector对象,操作的时候并没有加锁或排队之类的机制,如果有多个线程同时操作会发生什么情况。默认情况下由于操作的LEVEL是SIMPLE,默认的interval也比较大(113),因此对active、prev、next并发操作的情况会相对减少;leakCheckCnt是一个递增的操作,即使出错,也并不会造成严重的影响。有空的时候需要再来测下并发情况下会产生什么情况

分享到:
评论

相关推荐

    Netty性能测试

    在“Netty性能测试”中,我们关注的是Netty在处理并发请求时的能力,以及它作为RPC(远程过程调用)框架的表现。 Netty 的高性能主要体现在以下几个方面: 1. **异步IO模型**:Netty采用了NIO(非阻塞I/O)模型,...

    TCP调试助手(基于Netty)

    对于开发者而言,【TCP调试助手(基于Netty)】不仅可以用于日常的TCP协议调试,还能在开发和测试网络服务时,快速定位问题,提高工作效率。通过深入理解和运用Netty框架,可以进一步提升TCP调试工具的功能性和灵活性...

    Netty实战 电子版.pdf_java_netty_服务器_

    3. **ByteBuf**:Netty提供了自己的ByteBuf类,作为缓冲区,它比Java的ByteBuffer更易用且高效,支持直接内存和堆内存操作,避免了频繁的内存复制。 4. **零拷贝**:Netty通过使用FileRegion实现零拷贝,减少了CPU...

    Netty实战.epub_netty实战epub_netty实战epub_netty_

    此外,还会涉及ByteBuf,这是Netty提供的高效内存管理工具,用于替代Java的ByteBuffer,提供更友好的API和更好的性能。 Netty的案例实战部分可能会涵盖常见网络协议的实现,如HTTP、HTTPS、FTP、WebSocket等,这些...

    netty-netty-4.1.69.Final.tar.gz

    9. **心跳与空闲检测**:Netty提供心跳机制和空闲检测,以保持连接的活跃状态并及时发现死连接。 10. **文档与社区支持**:Netty有详尽的官方文档和活跃的社区,为开发者提供强大的支持。 下载并解压“netty-netty...

    深入浅出Netty_netty_

    除此之外,Netty还提供了强大的心跳检测机制,可以防止因网络延迟或故障导致的连接僵死。其优雅的关闭机制也能确保在系统关闭时,所有正在处理的连接都能得到妥善处理。 总之,《深入浅出Netty》会带你深入理解...

    Netty-API-文档中文版

    4. **高效的内存管理**:Netty 使用ByteBuf作为字节缓冲区,它提供了一种更高效的方式管理网络通信中的内存,避免了Java原生的ByteBuffer带来的性能损耗。 5. **强大的编码解码器**:Netty 提供了各种编码解码器,...

    netty所需要得jar包

    - Netty提供了许多性能优化选项,如自定义ByteBuf分配器、心跳机制、通道空闲检测等。 10. **错误处理与异常安全**: - Netty提供了一套完善的异常处理机制,确保即使在出错时也能优雅地关闭资源。 综上所述,...

    netty 实现长连接

    5. **ByteBuf**:Netty自定义的内存管理机制,用于高效地读写数据,避免了Java NIO中的Buffer频繁复制。 6. **拆包与合包**:Netty通过解码器和编码器处理不同大小的消息,确保消息的完整传输,即使它们被分片在...

    Netty管道测试代码

    此外,Netty 还提供了方便的测试工具,如 `EmbeddedChannel`,它允许在内存中创建并直接控制一个 Channel 和其 Pipeline,这对于单元测试非常有用。通过这种方式,开发者可以在不依赖实际网络环境的情况下,高效地...

    netty整合SpringMVC实现下载

    - ByteBuf:Netty 提供的高效内存管理工具,用于在网络传输中复用和管理字节数据。 2. **SpringMVC 的核心组件**: - DispatcherServlet:负责接收请求并分发到相应的处理器。 - Controller:处理业务逻辑,通常...

    netty5.0官方自带的demo

    它提供了动态扩容和精细化的内存管理,用于存储和传输数据。 - **Decoder与Encoder**:Netty提供了一系列预定义的编解码器,如LineBasedFrameDecoder、LengthFieldBasedFrameDecoder等,用于处理不同格式的数据。...

    Netty实战-Netty.zip

    6. **心跳与空闲检测**:Netty 内置了心跳机制和空闲状态检测,可以防止网络连接长时间无交互导致的问题。 7. **强大的异常处理**:Netty 提供了统一的异常处理机制,可以优雅地处理网络通信过程中的各种异常。 8....

    netty框架图及netty面试知识点解析

    5. Netty的内存管理:比如ByteBuf的使用和池化策略。 6. 高级特性:例如零拷贝技术、心跳检测、通道管道的自定义等。 7. Netty在实际项目中的应用案例:如RPC框架、消息队列、分布式系统等。 Netty学习.docx文档...

    用netty实现文件传输

    总结,利用 Netty 实现文件传输是一个涉及网络编程、多线程、I/O 操作以及内存管理的综合实践。通过 Netty 的强大功能,我们可以构建高效、可靠的文件传输系统。在实际应用中,还需要考虑到性能优化、安全性以及异常...

    netty权威指南 第二版 李林锋pdf

    此外,Netty的内存池设计也是其高性能的关键。 9. **实战案例**:书中可能包含实际项目中的应用示例,例如构建WebSocket服务器、实现RPC框架、处理HTTP请求等,帮助读者将理论知识应用于实践。 10. **源码分析**:...

    Netty-入门Netty编码

    总之,Netty 是一个强大的网络通信框架,它的异步模型、高效的内存管理和丰富的组件库使它在处理高并发网络应用时表现出色。通过 TimeServer 和 TimeClient 示例,我们可以逐步掌握 Netty 的基本用法,并为进一步...

    Netty性能测试报告.pdf

    测试环境配置为8核CPU、8GB内存的服务器,分别在不同端口运行Resin 4、Resin Pro 3.0.21和Netty,并且调整了JVM参数,以及客户端机器的系统环境参数。 在测试过程中,Resin-4在40960并发请求、4096字节数据大小的...

    netty-netty-4.1.32.final-remark.zip

    "final" 表示这是该版本的最终发布,通常意味着经过了充分测试和稳定。"remark" 暗示这个压缩包可能包含了一些注解或说明,可能是对这个特定版本的一些关键特性、优化或注意事项的解释。 描述中的 "tony老师netty" ...

    Netty大纲-同步netty专栏

    - **聊天室案例**:展示了如何利用Netty实现登录、单聊、群聊和空闲检测等功能。 5. **Netty优化** - **序列化算法**:Netty可以扩展不同的序列化算法以提高数据交换效率。 - **参数调优**:涉及连接超时、连接...

Global site tag (gtag.js) - Google Analytics