解码消息时内存不足异常

Out of memory exception while decoding message

提问人:zilon co 提问时间:11/16/2023 最后编辑:Denis Michealzilon co 更新时间:11/16/2023 访问量:78

问:

public static byte[] EncodeMessage(string message)
{
    try
    {
        // Convert the string message to a byte array
        byte[] messageBytes = System.Text.Encoding.UTF8.GetBytes(message);

        // Write the message length as a 4-byte integer followed by the message data
        byte[] lengthBytes = BitConverter.GetBytes(messageBytes.Length);
        byte[] sendBuffer = new byte[lengthBytes.Length + messageBytes.Length];
        Array.Copy(lengthBytes, sendBuffer, lengthBytes.Length);
        Array.Copy(messageBytes, 0, sendBuffer, lengthBytes.Length, messageBytes.Length);

        return sendBuffer;
    }
    catch (EncoderFallbackException ex)
    {
        // Handle encoding error (e.g., log, throw, or return a default value)
        Console.WriteLine($"Error encoding message: {ex.Message}");
        return null; // or throw an exception or return a default value
    }
    catch (Exception ex)
    {
        return null;
    }
}

public static string DecodeMessage(byte[] data)
{
    try
    {
        // Read the 4-byte header to get the length of the message
        byte[] lengthBytes = new byte[4];
        Debug.WriteLine(data.Length.ToString());
        Array.Copy(data, lengthBytes, lengthBytes.Length);
        int messageLength = BitConverter.ToInt32(lengthBytes, 0);
        // Read the message data into a byte array
        byte[] messageData = new byte[messageLength];
        Array.Copy(data, lengthBytes.Length, messageData, 0, messageLength);
        // Convert the message data to a string
        string message = System.Text.Encoding.UTF8.GetString(messageData);
        return message;
    }
    catch (Exception ex)
    {
        return null;
    }
}

我在这一行的功能中出现了内存不足异常。总的来说,当更改(如5762781类似的东西)时,它会在其他方面(如 4561 等)出现内存不足异常,然后它工作正常,没有问题)。我在这里做错了什么?DecodeMessageint messageLength = BitConverter.ToInt32(lengthBytes, 0)messageLength

我也尝试了字节序,但没有用。

C# 异常 Blazor

评论

2赞 ℍ ℍ 11/16/2023
您确定哪一行抛出错误吗?

答:

2赞 Ben 11/16/2023 #1

这是我在这里看到的:

  1. 函数中的 your 可能是由于分配的内存不足来读取消息数据。OutOfMemoryExceptionDecodeMessage

  2. 当消息长度较大时,该方法会尝试分配一个更大的字节数组,该数组可能会超过可用内存。messageData

为了有效地处理较大的消息并防止与内存相关的问题,您可以选择流式传输数据,而不是一次读取整个消息。这样,您就可以在较小或可管理的数据块中处理消息。

我建议你使用 try catch 来捕获错误并使用MemoryStream

public static string DecodeMessage(byte[] data)
{
   try
   {
       using (MemoryStream memoryStream = new MemoryStream(data))
       {
        // Read the 4-byte header to get the length of the message
        byte[] lengthBytes = new byte[4];
        memoryStream.Read(lengthBytes, 0, lengthBytes.Length);
        int messageLength = BitConverter.ToInt32(lengthBytes, 0);

        // Read the message data into a byte array
        byte[] messageData = new byte[messageLength];
        int bytesRead = 0;
        int bytesToRead = messageLength;

        while (bytesToRead > 0)
        {
            int chunkSize = memoryStream.Read(messageData, bytesRead, bytesToRead);
            if (chunkSize <= 0)
            {
                throw new EndOfStreamException("Unexpected end of stream");
            }

            bytesRead += chunkSize;
            bytesToRead -= chunkSize;
        }
        // Convert the message data to a string
        string message = System.Text.Encoding.UTF8.GetString(messageData);
        return message;
       }
   }
   catch (Exception ex)
   {
       Console.WriteLine($"Error decoding message: {ex.Message}");
       return null;
   }
}

评论

1赞 zilon co 11/16/2023
我试过了,但仍然没有内存问题
0赞 Ben 11/16/2023
是否有错误或崩溃,您可以显示日志吗?
3赞 Selvin 11/16/2023
不允许使用聊天 GPT 答案
1赞 JonasH 11/16/2023 #2

我无法发现任何特定错误。但是,如果目标只是将字符串转换为字节,然后再转换回来,那么您自己就会变得复杂。只需使用 StreamWriter/StreamReader:

[Test]
public void EncodeDecodeTest()
{
    var targetMs = new MemoryStream();
    var message = "hello world";
    EncodeMessage(targetMs, message);
    var bytes = targetMs.ToArray();
    var sourceMs = new MemoryStream(bytes);
    var result = DecodeMessage(sourceMs);
    Assert.AreEqual(result, message);
}

public void EncodeMessage(Stream target, string message)
{
    using var sw = new StreamWriter(target, Encoding.UTF8, 4096, leaveOpen:true);
    sw.Write(message);
}

public string DecodeMessage(Stream source)
{
    using var sr = new StreamReader(source, Encoding.UTF8, false, 4096, leaveOpen: true);
    return sr.ReadToEnd();
}

在读取或写入数据时,通常应尝试使用流,因为这允许您直接处理文件或网络流,而无需缓冲内存中的所有内容。如果你需要一个实际的字节数组,可以很容易地将内存流转换为字节,反之亦然,如示例所示。或者,如果要将整个对象转换为字节,请使用序列化库,如 json。

其他需要检查的事项是消息长度,6Mb 字符串应该不会导致任何问题,但如果您开始接近 2Gb,则有一些限制可能会导致问题。您可能还需要检查是否在 x64 而不是 x86 中运行,以确保您确实有可用内存。使用已知输入编写单元测试也非常有用,因此您可以确认功能是否正常工作,而无需考虑应用程序的其余部分。