解码消息时触发OutOfMemoryException的问题排查
解码大长度消息触发OutOfMemoryException的排查与解决
我编写了C#编码和解码消息的方法,在调用DecodeMessage方法时,于
int messageLength = BitConverter.ToInt32(lengthBytes, 0)行触发了OutOfMemoryException(实际异常由后续创建数组操作抛出,栈信息可能指向该行)。当messageLength值较大(如5762781)时会出现该异常,值较小时(如4561)则运行正常。已尝试调整字节序但未解决问题,请问哪里出错了?
原代码
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; } }
核心问题分析
你遇到的OutOfMemoryException并非BitConverter.ToInt32直接抛出,而是后续执行new byte[messageLength]时触发的。根源是解析出的messageLength远大于实际可用的消息数据长度,导致尝试创建一个超出内存容量的数组。常见原因有两个:
- 数据不完整:传入
DecodeMessage的data数组不是完整的编码结果(比如网络传输时只接收了部分字节)。此时前4个字节可能是截断的,解析出的messageLength是错误的超大值,甚至是负数(转成无符号整数后会变成极大值)。 - 字节序不匹配:虽然你尝试调整字节序,但可能没做到编码和解码完全一致。
BitConverter依赖当前系统的字节序(小端/大端),如果编码和解码在不同字节序的系统上运行,会解析出完全错误的长度值。
解决步骤
1. 增加数据合法性校验
在解码前必须验证data的长度是否足够,避免解析错误长度:
public static string DecodeMessage(byte[] data) { // 校验数据长度至少包含4字节的长度头 if (data == null || data.Length < 4) return null; try { byte[] lengthBytes = new byte[4]; Array.Copy(data, lengthBytes, 4); int messageLength = BitConverter.ToInt32(lengthBytes, 0); // 校验消息长度是否合法:不能为负,且总数据长度要足够容纳消息体 if (messageLength < 0 || messageLength > data.Length - 4) return null; byte[] messageData = new byte[messageLength]; Array.Copy(data, 4, messageData, 0, messageLength); return System.Text.Encoding.UTF8.GetString(messageData); } catch (Exception ex) { // 建议记录异常日志,而不是直接返回null return null; } }
2. 统一字节序(跨平台场景)
如果编码和解码可能在不同字节序的系统上运行,要放弃依赖BitConverter的默认行为,改用固定字节序(比如小端,多数系统默认):
- 编码时强制转成小端:
// 替换EncodeMessage中的lengthBytes生成逻辑 byte[] lengthBytes = BitConverter.GetBytes(messageBytes.Length); if (!BitConverter.IsLittleEndian) Array.Reverse(lengthBytes); // 转成小端
- 解码时按小端解析:
// 替换DecodeMessage中的messageLength解析逻辑 byte[] lengthBytes = new byte[4]; Array.Copy(data, lengthBytes, 4); if (!BitConverter.IsLittleEndian) Array.Reverse(lengthBytes); // 转成当前系统字节序再解析 int messageLength = BitConverter.ToInt32(lengthBytes, 0);
3. 排查数据传输完整性
如果是网络场景,要确保接收端完整接收了编码后的所有字节。比如用循环接收直到获取到足够的字节数,而不是只接收一次就解码。
内容的提问来源于stack exchange,提问作者zilon co
相关产品推荐
相关产品推荐

