Xamarin app performance degrading over time, eventually leading to crash

試著忘記壹切 提交于 2019-12-25 02:44:23

问题


I'm currently developing a Xamarin app that communicates via a Wi-Fi connection with some custom hardware containing a sensor. The job of my app is to retrieve the sensor data from the hardware and display it with oxyplot as a continuous stream of 1-D data. Unfortunately, I noticed that the performance of my app usually degrades over time and at some point it always crashes. The exact crashing time is quite arbitrary but seems to depend on the amount of sensor data (i.e. larger amplitude values result in faster app crashes). Some typical debug output before the app crashes is shown below:

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

This is the method containing the main loop in which I update the plot:

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();
}

The method getting called in every iteration is listed below:

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();
}

What have I tried already?

  1. My first guess was that oxyplot might be the culprit, which is why I introduced a flag with which I can disable the plotting of my data. Unfortunately, the app still crashes at some point even if no data is being plotted at all.
  2. On StackOverflow I read that "Skipped XX frames! The application may be doing too much work on its main thread" might be the problem. Thus, I decided to use the RunOnUiThread method but that just resulted in the data not being processed at all.
  3. Another idea was to introduce a timeout for the async method. That works okayish but has the disadvantage that after a while the timeout threshold is hit in every iteration and the app doesn't seem to return to "business as usual".

Any additional ideas are warmly welcome and any input is highly appreciated. Thank you.

Update

This is how the main method looks after introducing some timeout and cleanup logic:

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

来源:https://stackoverflow.com/questions/55049259/xamarin-app-performance-degrading-over-time-eventually-leading-to-crash

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!