首先和最重要的,
提前感谢所有可能提供帮助、批评和建议的人。
语言: 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;
}