Xamarin应用程序的性能会随着时间而下降,最终导致崩溃

时间:2019-03-07 17:04:11

标签: android xamarin async-await oxyplot

我目前正在开发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();
}

我已经尝试了什么?

  1. 我的第一个猜测是oxyplot可能是罪魁祸首,这就是为什么我引入了一个标志来禁用数据绘制的原因。不幸的是,即使根本没有绘制任何数据,该应用程序仍会在某个时刻崩溃。
  2. 在StackOverflow上,我read表示“跳过XX帧!应用程序可能在其主线程上做太多工作”。因此,我决定使用use RunOnUiThread方法,但这只是导致根本不处理数据。
  3. 另一个想法是introduce a timeout使用异步方法。这样做可以正常工作,但缺点是,每次迭代都达到了超时阈值一段时间后,该应用似乎无法恢复“照常营业”。

任何其他想法都将受到热烈欢迎,我们将不胜感激。谢谢。

更新

这是引入一些超时和清除逻辑后主要方法的外观:

    [...]
    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();

0 个答案:

没有答案