1

我在 Netty 中有两个场景,我试图最小化内存副本并优化内存使用:

(1) 读取一个非常大的帧(20 兆比特)。

(2) 读取大量非常小的帧(20 兆比特,每帧 50 比特)以在管道中的更高级别重建为一条消息。

对于第一种情况,当我在帧的开头得到一个长度时,我扩展了 FrameDecoder。不幸的是,由于我没有看到如何将长度返回给 Netty(我只指出帧是否完整),我相信 Netty 正在经历多个填充缓冲区、复制和重新分配周期,因此使用的内存比所需的更多。我在这里缺少什么吗?或者如果我期望这种情况,我应该完全避免使用 FrameDecoder 吗?

在第二种情况下,我目前正在创建我使用 ChannelBuffers.wrappedBuffer 包装的所有小帧的链接列表(然后我可以将其包装在 ChannelBufferInputStream 中),但我再次使用的内存比我预期的要多得多(也许因为分配的 ChannelBuffers 有空闲空间?)。这是使用 Netty ChannelBuffers 的正确方法吗?

4

2 回答 2

2
  1. 有一个特殊版本的帧解码器,称为 LengthFieldBasedFrameDecoder。当您有带有消息长度的标头时,它很方便。它甚至可以通过给出偏移量来从标头中提取消息长度。

  2. 实际上, ChannelBuffers.wrappedBuffer 不会创建接收数据的副本,它会从给定缓冲区创建复合缓冲区,因此不会复制接收到的帧数据。如果您在代码中保存复合缓冲区/自定义包装器并忘记取消,则可能会发生内存泄漏。

这些是我遵循的做法,

  • 为长期存在的对象分配直接缓冲区,在使用时对其进行切片。

  • 当我想将多个缓冲区加入/编码成一个大缓冲区时。我使用 ChannelBuffers.wrappedBuffer

  • 如果我有一个缓冲区并且想对它/它的一部分做某事,我通过在通道缓冲区实例上调用 slice 或 slice(0,..) 来制作它的一个片段

  • 如果我有一个通道缓冲区并且知道小数据的位置,我总是使用 getXXX 方法

  • 如果我有一个通道缓冲区,它在许多地方用于制作某些东西,请始终使其可修改,并在使用时对其进行切片。

注意:channelbuffer.slice 不会复制数据,它会创建一个带有新读写索引的通道缓冲区。

于 2011-11-21T18:27:51.757 回答
0

最后,处理我的 FrameDecoder 问题的最佳方法似乎是在 SimpleChannelUpstreamHandler 之上编写我自己的。一旦我从标题中确定了长度,我就创建了大小与长度完全匹配的 ChannelBuffer。这(连同其他更改)显着提高了我的应用程序的内存性能。

于 2012-01-18T17:33:22.413 回答