C# TCP 服务器/客户端对象传输/序列化/反序列化越来越多地使用内存帮助需要



首先和最重要的,

提前感谢所有可能提供帮助、批评和建议的人。

语言: C#


目标:用于图像和对象传输的TCP服务器/客户端。


服务器场景:服务器将侦听客户端连接。

客户端连接时,服务器将从套接字接收字节[]数据

服务器将 byte[] 转换为 (Type) 对象。

然后,服务器将使用此(类型)对象来更新 WPF 图像控件


客户端方案:

客户端将创建准备传输的对象。

客户端将对象转换为存储的字节[]。

客户端将连接到服务器并通过套接字发送对象


问题:

我不确定为什么这个过程每秒增加 60-100MB 的内存。

我想知道 Byte[] 分块是否是一个值得的解决方案(如果是这样,请您引导我到资源或提供解决方案)

感觉它没有正确清理自己或重用变量。


笔记:

位图捕获并转换为字节[]工作得很好 AFAIK 这不是问题,但如果问题不在下面的代码中,或者其他人会受益,我可以发布代码。

ObjecttoByte[] 和 ByteArrayToObject 代码可以工作,并且从其他堆栈溢出帖子中略有修改,就像明智的一样,如果问题不在下面的代码中,或者其他人会受益,我可以发布它。


服务器侦听器代码:

public void StartServer()
    {
        //-------------------------------------------------------
        // Initialize Variables For Server
        //-------------------------------------------------------   
        int recv;
        byte[] data;
        //-------------------------------------------------------
        // Configure Server Listener
        //-------------------------------------------------------   
        IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
        Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //-------------------------------------------------------
        // Bind Socket To IPEndpoint And Listen
        //-------------------------------------------------------   
        newsock.Bind(ipep);
        newsock.Listen(10);
        //-------------------------------------------------------
        // Accept New Connection
        //-------------------------------------------------------   
        Console.WriteLine("Waiting for a client...");
        Socket client = newsock.Accept();
        //-------------------------------------------------------
        // Verify Client Endpoint Connection
        //-------------------------------------------------------   
        IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;
        Console.WriteLine("Connected with {0} at port {1}", clientep.Address, clientep.Port);
        //-------------------------------------------------------
        // Start Reading From Socket While Client Connected
        //-------------------------------------------------------   
        while (client.Connected)
        {
            data = new byte[500000]; // Create Buffer For Object
            recv = client.Receive(data); // Ensure Client Has Sent Data
            if (recv == 0)
                break;
            //-------------------------------------------------------
            // Create Test Object And De-Serialize 
            //-------------------------------------------------------   
            TestObject to = new TestObject(); //Object For Storage
            Console.WriteLine("Server Object Size: " + data.Length); // Check Length For Interest
            var dataToObject = ByteArrayToObject(data); // Convert Object Byte[] to Object
            to = (TestObject)dataToObject; // Store Converted Byte[] Object into Typed Object
            Console.WriteLine("Server De-Serialized Object from Client."); // Provide Information
            Console.Out.WriteLine("Server TestObject: " + to.testString); // Extract And Notify Object String Data
            //-------------------------------------------------------
            // Update Main GUI Image (WPF)
            //-------------------------------------------------------   
            this.Dispatcher.Invoke((Action)(() =>
            {
                TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap)); // Create Type Converter
                Bitmap bitmap1 = (Bitmap)tc.ConvertFrom(to.testBmp); // Cast into Bitmap from Byte[] 
                imgRemoteDisplay.Source = ByteMonImaging.GetBitmapSource(bitmap1); // Display Bitmap  
                bitmap1 = null;
                tc = null;
            }));
            //-------------------------------------------------------
            // Clean Up
            //-------------------------------------------------------   
            dataToObject = null;
            data = null;
            to = null;
            GC.Collect();
            //-------------------------------------------------------
        }
        Console.WriteLine("Disconnected from {0}", clientep.Address);
        //-------------------------------------------------------
        // Close Listener
        //-------------------------------------------------------   
        client.Close();
        newsock.Close();
    }

客户端连接代码:

public void ConnectClient()
    {
        //-------------------------------------------------------
        // Configure Server Connection
        //-------------------------------------------------------
        IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
        Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //-------------------------------------------------------
        // Establish Connection To Server
        //-------------------------------------------------------
        try
        {
            server.Connect(ipep);
        }
        catch (SocketException e)
        {
            Console.WriteLine("Unable to connect to server.");
            Console.WriteLine(e.ToString());
            return;
        }
        //-------------------------------------------------------
        // Start Sending Object To Server While Connected
        //-------------------------------------------------------            
        while(server.Connected)
        {
            TestObject to = new TestObject(); // Create blank object store
            to.testString = "TestObject String Here"; // Set Blank Object Test String
            var bmpToSend = ByteMonImaging.CaptureBitmap(); // Set Blank Object Test  Bitmap
            to.testBmp = ByteMonImaging.ImageToByte(bmpToSend); // Convert Bitmap to Byte[]    
            var byteArray = ObjectToByteArray(to); // Pack Object into Byte[]
            Console.WriteLine("Client Object Size: " + byteArray.Length); // Curious Byte[] Size
            server.Send(byteArray); // Send Byte[] Object Via TCP
            Console.WriteLine("Client Sent Serialized Object to Server."); // Notify Where We Are At
            bmpToSend = null; // Clean Up
            to = null; // Clean Up
            byteArray = null; // Clean Up
            GC.Collect(); // Clean Up (Added for Checks)
        }
        //-------------------------------------------------------
        // Close Connection to Socket And Server
        //-------------------------------------------------------      
        Console.WriteLine("Disconnecting from server...");
        server.Shutdown(SocketShutdown.Both);
        server.Close();
    }

内存消耗的原因位于

//-------------------------------------------------------
            // Update Main GUI Image (WPF)
            //-------------------------------------------------------   
            this.Dispatcher.Invoke((Action)(() =>
            {
                TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap)); // Create Type Converter
                Bitmap bitmap1 = (Bitmap)tc.ConvertFrom(to.testBmp); // Cast into Bitmap from Byte[] 
                imgRemoteDisplay.Source = ByteMonImaging.GetBitmapSource(bitmap1); // Display Bitmap  
                bitmap1 = null;
                tc = null;
            }));

解决方案:问题是hBitmap在调用时导致内存泄漏。使用 finally 子句,我能够使用 externdll 删除对象。

 [DllImport("gdi32")]
    static extern int DeleteObject(IntPtr ipObj);
 public static BitmapSource GetBitmapSource(Bitmap bmp)
    {
        IntPtr hBitmap = bmp.GetHbitmap();
        System.Windows.Media.Imaging.BitmapSource b;
        try
        {                                
             b = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    hBitmap,
                    IntPtr.Zero,
                    System.Windows.Int32Rect.Empty,
                    System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
        }
        finally
        {
            DeleteObject(hBitmap);
        }
        return b;
    }

解决方案:问题是hBitmap在调用时导致内存泄漏。使用 finally 子句,我能够使用 externdll 删除对象。

 [DllImport("gdi32")]
    static extern int DeleteObject(IntPtr ipObj);
 public static BitmapSource GetBitmapSource(Bitmap bmp)
    {
        IntPtr hBitmap = bmp.GetHbitmap();
        System.Windows.Media.Imaging.BitmapSource b;
        try
        {                                
             b = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    hBitmap,
                    IntPtr.Zero,
                    System.Windows.Int32Rect.Empty,
                    System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
        }
        finally
        {
            DeleteObject(hBitmap);
        }
        return b;
    }

最新更新