使用BinaryFormatter进行反序列化会产生OutOfMemoryException

时间:2011-08-28 20:56:38

标签: c# serialization

我正在尝试让客户端应用程序将'MessageObject'发送到服务器应用程序。

每次我尝试反序列化服务器上​​的MessageObject时,都会出现OutOfMemoryException。


首先,这是 MessageObject 类:

[Serializable]
    public class MessageObject : ReplicableObject {
        public string Command;
        public string[] Parameters;

        public MessageObject() {

        }

        public MessageObject(string command, string[] parameters) {
            Command = command.ToLower();
            Parameters = parameters;
        }
    }

MessageObject是 ReplicableObject 的子级。这是 ReplicableObject

[Serializable]
    public abstract class ReplicableObject {
        public string UniqueID {
            get {
                if (uniqueID == "" || uniqueID == null) {
                    uniqueID = DateTime.Now.Subtract(new DateTime(1990, 1, 1)).TotalMilliseconds.ToString();
                    uniqueID = uniqueID.Substring(uniqueID.Length / 2) + Engine.Random(1000000, 9999999).ToString();
                }
                return uniqueID; 
            }
            private set { uniqueID = value; }
        }
        private string uniqueID;

        [NonSerialized]
        public bool RequiresReplication = true;

        public ReplicableObject() {
            uniqueID = DateTime.Now.Subtract(new DateTime(1990, 1, 1)).TotalMilliseconds.ToString();
            uniqueID = uniqueID.Substring(uniqueID.Length / 2) + Engine.Random(1000000, 9999999).ToString();
        }
    }

当客户端准备好向服务器发送MessageObject时,这是它使用的代码:

public static void SerializeRO(Stream stream, ReplicableObject ro) {
            Formatter.Serialize(stream, ro);
            stream.Write(ASCIIEncoding.ASCII.GetBytes("endhtobject"), 0, 11);
        }

TerminationString 是:

public static byte[] TerminationString = ASCIIEncoding.ASCII.GetBytes("endhtobject");

一旦服务器收到数据,就会调用此方法(这是抛出异常的地方):

public static ReplicableObject CheckByteStringForRO(byte[] byteString) {
            int tStringIndex = 0;
            for (int i = 0; i < byteString.Length; ++i) {
                if (byteString[i] == TerminationString[tStringIndex]) {
                    ++tStringIndex;
                    if (tStringIndex >= TerminationString.Length) {
                        MemoryStream ms = new MemoryStream();
                        ms.Write(byteString, 0, i - 10);
                        ms.Position = 0;
                        ReplicableObject ro = (ReplicableObject) Formatter.Deserialize(ms);
                        ms.Close();
                        return ro;
                    }
                }
                else tStringIndex = 0;
            }
            return null;
        }

上述大多数方法只是搜索TerminationString,所以这里有重要的一行:

MemoryStream ms = new MemoryStream();
                            ms.Write(byteString, 0, i - 10);
                            ms.Position = 0;
                            ReplicableObject ro = (ReplicableObject) Formatter.Deserialize(ms);
                            ms.Close();
                            return ro;

在启动'ReplicableObject ro ='的行上,抛出OutOfMemoryException。我不明白这是怎么发生的,特别是考虑到我发送的对象很小。

我应该指出,我是通过网络发送序列化数据的新手,所以我可能在这方面做错了。

如果您需要澄清任何内容,请发表评论。 :)

谢谢。


编辑:按要求堆叠异常跟踪:

  

mscorlib.dll中!System.Runtime.Serialization.Formatters.Binary.BinaryObjectWithMap.Read(System.Runtime.Serialization.Formatters.Binary ._ BinaryParser   输入=   {System.Runtime.Serialization.Formatters.Binary。 _BinaryParser})+   0x4f字节
    mscorlib.dll中!System.Runtime.Serialization.Formatters.Binary ._的 BinaryParser.ReadObjectWithMap(System.Runtime.Serialization.Formatters.Binary.BinaryHeaderEnum   binaryHeaderEnum)+ 0x38字节
    mscorlib.dll中!System.Runtime.Serialization.Formatters.Binary。
_BinaryParser.Run()   + 0x304字节
    mscorlib.dll中!System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(System.Runtime.Remoting.Messaging.HeaderHandler   handler = null,   System.Runtime.Serialization.Formatters.Binary .__ BinaryParser   serParser,bool fCheck,bool isCrossAppDomain,   System.Runtime.Remoting.Messaging.IMethodCallMessage methodCallMessage   = null)+ 0xaf字节
    mscorlib.dll中!System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(System.IO.Stream   serializationStream,System.Runtime.Remoting.Messaging.HeaderHandler   handler,bool fCheck,bool isCrossAppDomain,   System.Runtime.Remoting.Messaging.IMethodCallMessage   methodCallMessage)+ 0xcf bytes
    mscorlib.dll中!System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(System.IO.Stream   serializationStream)+ 0x10字节

     
    

HolotypeTwo.dll!HolotypeTwo.Engine.CheckByteStringForRO(字节[]     byteString = {byte [8192]})第34行+ 0x10字节C#       HolotypeServer.exe!HolotypeServer.UnauthorisedPlayer.StartListening()     第27行+ 0x8字节C#       mscorlib.dll中!System.Threading.ThreadHelper.ThreadStart_Context(对象     状态)+ 0x63字节
      mscorlib.dll中!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext     executionContext,System.Threading.ContextCallback回调,对象     state,bool ignoreSyncCtx)+ 0xb0 bytes
      mscorlib.dll中!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext     executionContext,System.Threading.ContextCallback回调,对象     状态)+ 0x2c字节
      mscorlib.dll!System.Threading.ThreadHelper.ThreadStart()+ 0x44     字节

  

1 个答案:

答案 0 :(得分:0)

您是否检查过您要反序列化的内容?由于代码中存在缺陷,您可能偶尔会在流中获取两个对象。如果在标记之前发生'e'字节,则CheckByteStringForRO方法最终可能会跳过其终止标记。为了正确捕捉这种情况,你的其他条件必须是:

else
{
    tStringIndex = 0;

    if (byteString[i] == TerminationString[tStringIndex])
    {
        tStringIndex++;
    }
}

另外,为什么不只是制作一个对象的集合并序列化它而不是使用终止标记呢?