В настоящее время я разрабатываю приложение Xamarin, которое взаимодействует через соединение Wi-Fi с некоторым нестандартным оборудованием, содержащим датчик. Работа моего приложения состоит в том, чтобы получать данные датчика с аппаратного обеспечения и отображать их с помощью oxyplot в виде непрерывного потока 1-D данных. К сожалению, я заметил, что производительность моего приложения со временем обычно падает, и в какой-то момент он всегда падает. Точное время сбоя совершенно произвольно, но, похоже, зависит от количества данных датчика (то есть большие значения амплитуды приводят к более быстрым сбоям приложения). Ниже приведены некоторые типичные выходные данные отладки до сбоя приложения:
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();
}
Что я уже пробовал?
- Моим первым предположением было то, что виновником мог быть oxyplot, поэтому я ввел флаг, с помощью которого я могу отключить отображение своих данных. К сожалению, приложение в какой-то момент все еще падает, даже если данные вообще не отображаются.
- В StackOverflow I читайте , что «проблема может быть в том, что« Пропущено XX кадров! Приложение может выполнять слишком много работы в своем основном потоке ». Поэтому я решил использовать метод RunOnUiThread, но это просто привело к тому, что данные вообще не обрабатывались.
- Другая идея состояла в том, чтобы ввести тайм-аут для асинхронного метода. Это работает нормально, но имеет тот недостаток, что через некоторое время порог тайм-аута достигает каждой итерации, и приложение, похоже, не возвращается к «обычному бизнесу».
Любые дополнительные идеи горячо приветствуются, и любой вклад высоко ценится. Спасибо.
Обновление
Вот как выглядит основной метод после введения некоторой логики времени ожидания и очистки:
[...]
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();