开发者

Deserialization using BinaryFormatter produces OutOfMemoryException

I am trying to get a client application to send a 'MessageObject' to a server application.

Every time I try to deserialize the MessageObject on the server, I get an OutOfMemoryException.


First of all, here is the MessageObject class:

[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 is a child of ReplicableObject. Here is 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();
        }
    }

When the client is ready to send a MessageObject to the server, this is the code it uses:

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

TerminationString is:

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

Once the server receives the data, this method is called (this is where the exception is thrown):

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;
        }

Most of the above method is just searching for the TerminationString, so here are the important lines:

MemoryStream ms = new MemoryStream();
                            ms.Write(byteString, 0, i - 10);
                            ms.Position = 0;
                            ReplicableObject ro = (ReplicableObject) Formatter.Deserialize(ms);
                            ms.Close();
                            return ro;
开发者_如何学Go

On the line that starts 'ReplicableObject ro =', the OutOfMemoryException is thrown. I don't understand how this can happen, especially considering that the objects I'm sending are tiny.

I should point out that I'm new to sending serialized data over a network, so I may have done something wrong in that respect.

Please, leave a comment if you need clarification on anything. :)

Thank you.


Edit: Stack trace of exception as requested:

mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.BinaryObjectWithMap.Read(System.Runtime.Serialization.Formatters.Binary._BinaryParser input = {System.Runtime.Serialization.Formatters.Binary._BinaryParser}) + 0x4f bytes

mscorlib.dll!System.Runtime.Serialization.Formatters.Binary._BinaryParser.ReadObjectWithMap(System.Runtime.Serialization.Formatters.Binary.BinaryHeaderEnum binaryHeaderEnum) + 0x38 bytes

mscorlib.dll!System.Runtime.Serialization.Formatters.Binary._BinaryParser.Run() + 0x304 bytes

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 bytes

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 bytes

HolotypeTwo.dll!HolotypeTwo.Engine.CheckByteStringForRO(byte[] byteString = {byte[8192]}) Line 34 + 0x10 bytes C# HolotypeServer.exe!HolotypeServer.UnauthorisedPlayer.StartListening() Line 27 + 0x8 bytes C# mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x63 bytes

mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool ignoreSyncCtx) + 0xb0 bytes

mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x2c bytes

mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes


Have you checked the contents of what you are trying to Deserialize? You could be getting two objects in the stream occasionally due to a flaw in the code. Your CheckByteStringForRO method can end up skipping its termination marker if an 'e' byte occurs immediately before the marker. In order to properly catch that case your else condition needs to be:

else
{
    tStringIndex = 0;

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

Also, why not just make a collection of your objects and serialize that instead of using termination markers and all that?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜