StreamReader ReadLine内存泄漏

时间:2014-06-28 15:58:32

标签: c# memory tcpclient tcplistener

我正在制作服务器而且我注意到它有一些奇怪的内存泄漏。在我的服务器上,我限制了一个IP地址可以达到8的总连接数。这非常有效。

然而,当我使用LOIC来操作我的服务器时,我注意到虽然它只创建了8个网络类实例,但StreamReader的ReadLine方法占用了很大一部分内存。

An image of the VS Analyse

我已经使用Console.WriteLine验证了实际上没有收到任何数据,它只是等待该方法。内存增加并填满了我的整个16GB。

请注意,这个类中只有8个实例来自一个IP而且我正在做,而不是DDoS,它只来自我的IP(我已经验证了这一点)。

此问题的原因是什么?我该如何解决?

编辑:
相关代码是:

        string data;
        Dictionary<string, string> variables = null;
        try {

            while (_listen) {

                data = null;

                while ((data = _reader.ReadLine()) != null) {

1 个答案:

答案 0 :(得分:0)

ReadLine函数会将数据缓冲到一个字符串,它会遇到\r\n\n单独就不会这样做)。它使用StringBuilder。因此,如果您收到的数据不包含序列\r\n,那么它最终会为单个字符串分配大量内存。

这里有一个简单的解决方案:您必须限制服务器愿意读取的最大字符串长度。这是处理恶意数据所必需的 - 如果您的服务器可能是DoS攻击的受害者,则永远不要相信您收到的数据。

所以,解决方案,作为TextReader扩展方法:

public static String ReadLineSafe(this TextReader reader, int maxLength)
{ 
    var sb = new StringBuilder();
    while (true) {
        int ch = reader.Read();
        if (ch == -1) break; 
        if (ch == '\r' || ch == '\n')
        { 
            if (ch == '\r' && reader.Peek() == '\n') reader.Read(); 
            return sb.ToString();
        } 
        sb.Append((char)ch);

        // Safety net here
        if (sb.Length > maxLength)
            throw new InvalidOperationException("Line is too long");
    }
    if (sb.Length > 0) return sb.ToString();
    return null; 
}

这是原始ReadLine代码,添加了安全检查。

哦,你应该将你的NetworkStream包裹在BufferedStream中以进行网络阅读,以避免在每个字节上调用recv