我目前正在开发Xamarin应用,该应用可通过Wi-Fi连接与某些包含传感器的自定义硬件进行通信。我的应用程序的工作是从硬件中检索传感器数据,并使用oxyplot将其显示为一维连续数据流。不幸的是,我注意到我的应用程序的性能通常会随着时间的流逝而降低,并在某些时候总是崩溃。确切的崩溃时间是非常任意的,但似乎取决于传感器数据的数量(即,较大的振幅值会导致应用崩溃更快)。应用程序崩溃前的一些典型调试输出如下所示:
03-07 17:36:54.149 I/art (10777): Starting a blocking GC Explicit
03-07 17:36:54.164 I/art (10777): Explicit concurrent mark sweep GC freed 2991(107KB) AllocSpace objects, 0(0B) LOS objects, 39% free, 10MB/17MB, paused 174us total 14.883ms
03-07 17:36:54.168 D/Mono (10777): GC_TAR_BRIDGE bridges 1104 objects 1104 opaque 0 colors 1104 colors-bridged 1104 colors-visible 1104 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.06ms tarjan 0.28ms scc-setup 0.17ms gather-xref 0.01ms xref-setup 0.00ms cleanup 0.14ms
03-07 17:36:54.168 D/Mono (10777): GC_BRIDGE: Complete, was running for 20.42ms
03-07 17:36:54.168 D/Mono (10777): GC_MINOR: (Nursery full) time 3.34ms, stw 5.17ms promoted 211K major size: 3664K in use: 2807K los size: 14336K in use: 11300K
03-07 17:36:56.248 I/art (10777): Starting a blocking GC Explicit
03-07 17:36:56.263 I/art (10777): Explicit concurrent mark sweep GC freed 3093(111KB) AllocSpace objects, 0(0B) LOS objects, 39% free, 10MB/17MB, paused 180us total 14.729ms
03-07 17:36:56.267 D/Mono (10777): GC_TAR_BRIDGE bridges 1144 objects 1144 opaque 0 colors 1144 colors-bridged 1144 colors-visible 1144 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.07ms tarjan 0.30ms scc-setup 0.18ms gather-xref 0.01ms xref-setup 0.00ms cleanup 0.13ms
03-07 17:36:56.267 D/Mono (10777): GC_BRIDGE: Complete, was running for 21.07ms
03-07 17:36:56.267 D/Mono (10777): GC_MINOR: (Nursery full) time 3.60ms, stw 4.38ms promoted 216K major size: 3904K in use: 3055K los size: 18432K in use: 14810K
03-07 17:36:56.962 D/Mono (10777): GC_BRIDGE waiting for bridge processing to finish
03-07 17:36:56.968 I/art (10777): Starting a blocking GC Explicit
03-07 17:36:56.988 I/art (10777): Explicit concurrent mark sweep GC freed 1327(43KB) AllocSpace objects, 0(0B) LOS objects, 40% free, 10MB/17MB, paused 220us total 19.794ms
03-07 17:36:56.992 D/Mono (10777): GC_TAR_BRIDGE bridges 648 objects 649 opaque 0 colors 648 colors-bridged 648 colors-visible 648 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.11ms tarjan 0.29ms scc-setup 0.16ms gather-xref 0.01ms xref-setup 0.00ms cleanup 0.13ms
03-07 17:36:56.992 D/Mono (10777): GC_BRIDGE: Complete, was running for 25.65ms
03-07 17:36:56.992 D/Mono (10777): GC_MAJOR: (LOS overflow) time 16.50ms, stw 21.50ms los size: 5120K in use: 460K
03-07 17:36:56.992 D/Mono (10777): GC_MAJOR_SWEEP: major size: 3984K in use: 2657K
03-07 17:36:59.675 I/Choreographer(10777): Skipped 116 frames! The application may be doing too much work on its main thread.
03-07 17:37:01.298 I/art (10777): Starting a blocking GC Explicit
03-07 17:37:01.304 D/Mono (10777): GC_BRIDGE waiting for bridge processing to finish
03-07 17:37:01.314 I/art (10777): Explicit concurrent mark sweep GC freed 3078(111KB) AllocSpace objects, 0(0B) LOS objects, 40% free, 10MB/17MB, paused 173us total 15.393ms
03-07 17:37:01.319 D/Mono (10777): GC_TAR_BRIDGE bridges 1144 objects 1144 opaque 0 colors 1144 colors-bridged 1144 colors-visible 1144 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.07ms tarjan 0.33ms scc-setup 0.20ms gather-xref 0.02ms xref-setup 0.00ms cleanup 0.40ms
03-07 17:37:01.319 D/Mono (10777): GC_BRIDGE: Complete, was running for 23.28ms
03-07 17:37:01.319 D/Mono (10777): GC_MINOR: (Nursery full) time 3.76ms, stw 5.02ms promoted 216K major size: 4128K in use: 2905K los size: 5120K in use: 4050K
03-07 17:37:03.143 I/art (10777): Starting a blocking GC Explicit
03-07 17:37:03.158 I/art (10777): Explicit concurrent mark sweep GC freed 3070(110KB) AllocSpace objects, 0(0B) LOS objects, 40% free, 10MB/17MB, paused 252us total 14.860ms
03-07 17:37:03.161 D/Mono (10777): GC_TAR_BRIDGE bridges 1134 objects 1134 opaque 0 colors 1134 colors-bridged 1134 colors-visible 1134 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.07ms tarjan 0.30ms scc-setup 0.18ms gather-xref 0.01ms xref-setup 0.00ms cleanup 0.13ms
03-07 17:37:03.161 D/Mono (10777): GC_BRIDGE: Complete, was running for 20.60ms
03-07 17:37:03.161 D/Mono (10777): GC_MINOR: (Nursery full) time 3.40ms, stw 4.31ms promoted 216K major size: 4256K in use: 3153K los size: 9216K in use: 7680K
03-07 17:37:05.200 I/art (10777): Starting a blocking GC Explicit
03-07 17:37:05.216 I/art (10777): Explicit concurrent mark sweep GC freed 3008(108KB) AllocSpace objects, 0(0B) LOS objects, 39% free, 10MB/17MB, paused 182us total 15.827ms
03-07 17:37:05.219 D/Mono (10777): GC_TAR_BRIDGE bridges 1110 objects 1110 opaque 0 colors 1110 colors-bridged 1110 colors-visible 1110 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.07ms tarjan 0.32ms scc-setup 0.19ms gather-xref 0.01ms xref-setup 0.00ms cleanup 0.16ms
03-07 17:37:05.219 D/Mono (10777): GC_BRIDGE: Complete, was running for 21.94ms
03-07 17:37:05.219 D/Mono (10777): GC_MINOR: (Nursery full) time 3.70ms, stw 4.93ms promoted 208K major size: 4416K in use: 3393K los size: 13312K in use: 11258K
Thread finished: <Thread Pool> #4
Thread finished: <Thread Pool> #2
Thread started: <Thread Pool> #10
Thread finished: <Thread Pool> #3
Thread finished: #11
这是包含主循环的方法,我在其中更新绘图:
public static async Task MainMethodAsync(MyDisplay MyDisplayPlot, DateTime StartTime, MainPage mainPage) {
ToggleAccelerometer();
Accelerometer.ReadingChanged += Accelerometer_ReadingChanged;
Client = new MyClientSocket();
await Client.ConnectAndStartReadTaskAsync();
int FrameCounter = 0;
while (ShootContinuously) {
FrameCounter++;
await GetDataAndUpdateUIAsync(MyDisplayPlot,FrameCounter,StartTime,mainPage);
}
await Client.DisconnectAndStopReadTaskAsync();
}
下面列出了每次迭代中被调用的方法:
private static async Task GetDataAndUpdateUIAsync(MyDisplay MyDisplayPlot, int FrameCounter, DateTime StartTime, MainPage mainPage) {
ShootAsync();
await ReceiveAsync();
if (PlottingEnabledFlag) {
MyDisplayPlot.UpdateMyDisplayPlot();
}
DateTime CurrentTime = DateTime.Now;
double elapsedSecs = (CurrentTime - StartTime).TotalSeconds;
mainPage.Title = "Frames: " + FramesCounter.ToString() + ", Frames/s: " + System.Math.Round((FramesCounter / elapsedSecs), 3).ToString();
}
任何其他想法都将受到热烈欢迎,我们将不胜感激。谢谢。
这是引入一些超时和清除逻辑后主要方法的外观:
[...]
int timeout = 1000;
while (ShootContinuously) {
FrameCounter++;
CancellationToken cancellationToken = new CancellationToken();
var task = GetDataAndUpdateUIForContinuousShootingAsync(MyDisplayPlot, FrameCounter, StartTime, mainPage);
if (await Task.WhenAny(task, Task.Delay(timeout, cancellationToken)) == task) {
// Task completed within timeout.
// Consider that the task may have faulted or been canceled.
// We re-await the task so that any exceptions/cancellation is rethrown.
await task;
} else { // timeout/cancellation logic
Debug.WriteLine("Task is taking too long!");
await Client.DisconnectAndStopReadTaskAsync();
Client = null;
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
GC.WaitForPendingFinalizers();
Client = new MyClientSocket();
await Client.ConnectAndStartReadTaskAsync();
continue;
}
}
await Client.DisconnectAndStopReadTaskAsync();