C# 导致GC扫描并停止接收的连续UDP通信
我正在尝试从android设备与嵌入式UDP服务器通信,收到UDP数据包后,我正在更新我的UI。通信可以正常工作约250次迭代(查询-响应),然后弹出一个GC扫描主窗口,UDP套接字停止接收。我是android开发的新手,我不确定我的UDP通信的实现是否正确 这就是我所拥有的C# 导致GC扫描并停止接收的连续UDP通信,c#,xamarin.android,android-asynctask,udp,threadpool,C#,Xamarin.android,Android Asynctask,Udp,Threadpool,我正在尝试从android设备与嵌入式UDP服务器通信,收到UDP数据包后,我正在更新我的UI。通信可以正常工作约250次迭代(查询-响应),然后弹出一个GC扫描主窗口,UDP套接字停止接收。我是android开发的新手,我不确定我的UDP通信的实现是否正确 这就是我所拥有的 void Initialize_UDP() { ThreadPool.QueueUserWorkItem(o => UDPCommunicator()); update
void Initialize_UDP()
{
ThreadPool.QueueUserWorkItem(o => UDPCommunicator());
update_flag = true;
}
void UDPCommunicator()
{
while (true)
{
if (update_flag)
{
try
{
byte[] buffer = FrameGenerator(1, 0, true);
byte[] data = new byte[25];
CheckQuery(buffer);
var sender = default(IPEndPoint);
using (UdpClient udpClient = new UdpClient(15001))
{
udpClient.EnableBroadcast = true;
udpClient.Send(buffer, buffer.Length, "192.168.4.255", 15000);
udpClient.Client.ReceiveTimeout = 500;
data = udpClient.Receive(ref sender);
socket_active = false;
}
CheckResponse(data);
/*RunOnUiThread(() =>
{
Update_UI(data);
}); */
}
catch (SocketException)
{
Log.Debug("Error", "Socket Error: Timeout");
}
}
Thread.Sleep(100);
}
}
这是我收到的错误
电话:35681185623120223800021149185
09-2514:20:01.896承兑交单(7595):查询:358110139
09-25 14:20:01.941 I/zygote(7595):显式并发复制GC释放4890(372KB)AllocSpace对象,0(0B)LOS对象,50%空闲,1628KB/3MB,暂停170us总计35.511ms
09-25 14:20:01.941 D/Mono(7595):GC_TAR_桥接21对象24不透明1颜色21颜色桥接21颜色可见21外部参照0缓存命中0缓存半命中0缓存未命中0设置0.07ms tarjan 0.06ms scc设置0.06ms聚集外部参照0.00ms外部参照设置0.00ms清理0.05ms
09-25 14:20:01.942 D/Mono(7595):GC_桥接器:完成,运行37.27毫秒
09-25 14:20:01.942 D/Mono(7595):GC_小调:(同时启动)时间5.32毫秒,stw 8.02毫秒提升114K大调尺寸:848K使用中:170K服务水平尺寸:17408K使用中:16067K
09-25 14:20:01.942 D/Mono(7595):地面指挥系统(主要)同时启动:(服务水平溢出)
09-25 14:20:02.442 D/错误(7595):套接字错误:超时
09-25 14:20:02.544 D/A(7595):查询:35 81 10 139这是超时时间太短的情况。
UdpClient.Client.ReceiveTimeout
是以毫秒为单位的时间。Stacktrace显示,“GC\u主\u并发\u启动:(LOS溢出)”和“套接字错误:超时”之间的时间正好为500毫秒,因此这就是原因。解决方法是增加UDP客户端的超时,默认值为“0”,表示无限,和/或向超时事件添加错误处理,正如BugFinder&MindSwipe指出的那样,创建一个新的UdpClient every循环会给GC带来不必要的负载,更好的替代方法是重用解决了问题的UdpClient。此外,以异步方式使用UDP池还可以进一步提高性能。下面是我的实现(为简洁起见简化)
void初始化_UDP()
{
UdpClient UdpClient=新的UdpClient();
UdpClient r_UdpClient=新的UdpClient(15001);
IPEndPoint发送方=默认值(IPEndPoint);
ManualResetEventSlim接收=新的ManualResetEventSlim(真);
运行(()=>UDP_传输());
}
异步无效UDP_传输()
{
字节[]帧;
SelectFrameQueue(选择器);
UDP客户=新的UDP客户(15001);
udpClient.EnableBroadcast=true;
udpClient.BeginReceive(新的异步回调(UDP_接收),udpClient);
while(true)
{
对于(int i=0;i
{
ShowToast(“连接超时。请检查设备”);
});
};
等待任务。延迟(更新延迟);//从H/W释放压力
receive.Reset();
}
}
}
无效UDP_接收(IAsyncResult结果)
{
receive.Set();
r_UdpClient=result.AsyncState作为UdpClient;
data=r_UdpClient.EndReceive(结果,参考发送方);
RunOnUiThread(()=>
{
更新用户界面(数据);
});
r_UdpClient.BeginReceive(新的异步回调(UDP_接收),r_UdpClient);
}
您正在将UdpClient上的超时设置为500毫秒。GC在收集时冻结所有代码,看起来GC清理时间超过500 ms,或者添加了GC延迟,消息往返时间超过500 ms。只需将超时设置为更合理的时间,例如几秒钟,您是如何处理数据包丢失的?@BilalKazi不一定根据您展示的代码,您每次都会创建一个新的updclient,不要重复使用。。然后gcI不太同意BugFinder,创建一个新的UdpClient每个循环都会给GC带来不必要的负载。我建议您创建一次UdpClient,并在每次创建UdpClient时重用itnope,最终会有足够的内存混乱导致gc。通过拥有一个池,您可以处理多次,但保持内存使用,sameI将超时时间增加到5000毫秒,但这没有帮助。响应通常在200毫秒内从服务器收到,因此我认为“接收超时”不是原因。问题可能是来自服务器的UDP数据包没有到达。UDP不能保证数据包的可靠甚至有序传递(更多)。
void Initialize_UDP()
{
UdpClient udpClient = new UdpClient();
UdpClient r_UdpClient = new UdpClient(15001);
IPEndPoint sender = default(IPEndPoint);
ManualResetEventSlim receive = new ManualResetEventSlim(true);
Task.Run(() => UDP_Transmit());
}
async void UDP_Transmit()
{
byte[] frame;
SelectFrameQueue(selector);
udpClient = new UdpClient(15001);
udpClient.EnableBroadcast = true;
udpClient.BeginReceive(new AsyncCallback(UDP_Receive), udpClient);
while (true)
{
for (int i = 0; i < frame_Queue.Length; i++)
{
frame = FrameGenerator(frame_Queue[i]); //Generates Frames
try
{
udpClient.Send(frame, frame.Length, "192.168.4.255", 15000);
}
catch (SocketException)
{
Log.Debug("Error", "Socket Exception");
}
if(!receive.Wait(10000)) //Receive Timeout
{
RunOnUiThread(() =>
{
ShowToast("Connection Timeout. Please check device");
});
};
await Task.Delay(update_delay); //To release pressure from H/W
receive.Reset();
}
}
}
void UDP_Receive(IAsyncResult result)
{
receive.Set();
r_UdpClient = result.AsyncState as UdpClient;
data = r_UdpClient.EndReceive(result, ref sender);
RunOnUiThread(() =>
{
Update_UI(data);
});
r_UdpClient.BeginReceive(new AsyncCallback(UDP_Receive), r_UdpClient);
}