Memory problem with charts


#1

I am developing a Xamarin iOS app where Shinobi charts are shown in views that are embedded in a scrollview. 

Each view/page contains one chart + some additional controls. The user can swipe left/right on the scrollview to navigate through the different pages.

Each chart (donut chart actually) has a datasource with 1 to 10 elements.

If I have more than eight pages/charts, the app crashes. Is it normal that the charts take up so much memory?

The app crashes on the line AddSubview(_donutView) in the LayoutSubviews() method. There is no .NET exception, just a crash. Sometimes my app receives a memory warning from iOS first.

What I find strange is that the app crashes when the view is added as a subview. I would have expected it to crash for memory reasons at construction time of the chart. When I add any other control instead of a Shinobi chart (e.g. a UILabel or even a Shinobi grid) in LayoutSubviews, there is no problem.

When I profile my application using the Mono profiler tool from Xamarin, there is nothing special to see. My app only takes up about 2-3 MB of managed memory and there are no (managed) memory leaks.

Any idea?


#2

(post deleted)


#3

I managed to reproduce the problem area in a very simple C# test project. It has nothing to do with scrollviews whatsoever.

  • Root view controller = tab bar controller

  • Each tab page shows a view with a single Shinobi donut chart

  • When there are 5 tab pages / charts, the app is unstable on my iPad and crashes after a few taps (after a memory warning from iOS).

  • When there are more than 5 tab pages / charts, the app crashes at startup.

Is there a serious bug in ShinobiCharts or am I missing something very obvious?

The test project can be found here:

http://www.filedropper.com/shinobichartstest

I incidently left the ShinobiCharts.dll file out because it is the purchased version.

Can you please look into this? We bought a ShinobiSuite license yesterday to use in our app that is to be delivered next week. As the situation is now, the Chart control library is unusable for us.

But as I said, maybe (hopefully) I am missing something very obvious.


#4

Hi Boo-lee,

We will take a look at your project and see if we can spot the problem. Someone from the team will be back in touch on this thread as soon as possible.

Jan


#5

Thank you, Jan. I’m really looking forward to this. I desperately need a solutionif I want to deliver my app in time.


#6

Hi Boo-lee,

We’ve tested the app and it appears to be stable. It never crept above 1MB memory usage.

Can I ask, do you observe these results on device and/or simulator? If so which device? Could you try moving the addSubview call to your contructor, and see what effect that has? Also, be sure to kill any apps already running on the device.

Would it also be possible for you to send us the crash report? (it should tell us if iOS is killing the app due to memory issues or a different issue.)

Thanks,
Jan


#7

Hi Jan,

I only have the issue on the hardware device (an iPad 3), not in the simulator. I forgot to mention this, sorry for that. 

The test app is the only app running on my iPad (no other apps in memory).

When the app is running with 5 tab pages/charts, it starts up and I immediately get a memory warning:

2013-05-29 11:12:47.815 ShinobiChartsTest[2781:907] Received memory warning.

After a few taps, it crashes. Nothing is written in the application output window.

In my device log, the following crash report is written:

Incident Identifier: 52D459A0-F393-49A0-8D11-0167164BD364

CrashReporter Key:   e78e579cc60cdbd8ce29f219fcd45ca14b27f451

Hardware Model:      iPad3,3

OS Version:          iPhone OS 6.1.3 (10B329)

Kernel Version:      Darwin Kernel Version 13.0.0: Wed Feb 13 21:38:45 PST 2013; root:xnu-2107.7.55.2.2~1/RELEASE_ARM_S5L8945X

Date:                2013-05-29 11:12:08 +0200

Time since snapshot: 37 ms

Free pages:        130828

Active pages:      25203

Inactive pages:    12126

Throttled pages:   46830

Purgeable pages:   40

Wired pages:       30628

Largest process:   ShinobiChartsTes

Processes

     Name                    <UUID>                       rpages       recent_max       [reason]          (state)

   webbookmarksd <41a1bb7133063e13af5d04d5a4bed98b>          728              728                      (daemon) (idle)

networkd_privile <cd5f76fd767c31428f411ecf03540546>          169              169                      (daemon) (idle)

       accountsd <e6ceba0e6e053a3ea02d0a916903cff8>         1314             1314                      (daemon) (idle)

coresymbolicatio <b0c9f54634443ac7a86bade85c7be91c>          172              172                      (daemon) (idle)

    itunesstored <44d1bc6b3088390bb5c58d052a71f8f2>         1791             1791                      (daemon) (idle)

             lsd <566268cf717b335e98ddba10ca9315ab>          564              564                      (daemon) (idle)

mobile_assertion <dbd39dd04b2836fb8b29387b409f5c9a>          301              301                      (daemon) (idle)

        installd <117f65beb8cb38da8e0844256c65e402>          779              779                      (daemon) (idle)

           timed <129ae7acc9bc3209a60ac42d49b0d89f>          434              434                      (daemon) (idle)

            xpcd <27ba4c754cc3320fb864588368901246>          201              201                      (daemon) (idle)

AppleIDAuthAgent <b37f7a6048a33556a8230d3a759fc4ae>          265              265                      (daemon) (idle)

            afcd <3bd960d39c9f3972a10923db0e687b4a>          254              254                      (daemon) (idle)

        recentsd <3e01ce59923d3b0381c36d62682b58b8>          966              966                      (daemon) (idle)

      MobileMail <e07ca7a7280736c7bf301451f89d1c02>         2241             2241                      (resume) (continuous)

     MobilePhone <51866c9bc9f93c9d8526e8acf9efc64c>         1115             1115                      (resume) (continuous)

             kbd <f7341c9a161a39acb5bc18ea47d6ebb7>          572              572                      (daemon)

            tccd <2778744d99a530c9a7d5e57a19b60008>          345              345                      (daemon)

ShinobiChartsTes <3de5b625c3303ce69f104fb2803eb192>       174931           174931  [per-process-limit] (frontmost) (resume)

            ptpd <096297a7a40f318290a972274cc44d87>         1260             1260                      (daemon)

      aosnotifyd <47126a998bb5308f9d5cbe028dc47d60>          532              532                      (daemon)

           wifid <72eda25ccdd737a79d6cd172e9bf99a5>          557              557                      (daemon)

   iaptransportd <9b3cf56b4db13761bbd8ac2e0ff099be>          266              266                      (daemon)

       locationd <137100f254373daeb894f665c413f8b0>         1750             1750                      (daemon)

    mediaserverd <af72564bf8713fb8b16ee64c5ee85568>         1065             1065                      (daemon)

         syslogd <da215e2d3de133bf8f52590727b9bdfe>          269              269                      (daemon)

             atc <e89fdea9f8f8309ebc477543a61c078a>         2760             2760                      (daemon)

     dataaccessd <abc7f74d5d683d4c9a04e7ade5b1126b>         1834             1834                      (daemon)

     SpringBoard <bd1d77d154ef3dffbb53d89337c8a08f>        10325            10325                     

      backboardd <e1dc74434e0e3938b17ff0f7ad85d138>        12962            12962                      (daemon)

  UserEventAgent <7ee3410c25e4372d84e93318fe42696b>          956              956                      (daemon)

MobileStorageMou <50b60b597b29370cb2decbc484177aff>          214              214                      (daemon)

         lockbot <35258382783c3587b81fb0421e375bb0>          144              144                      (daemon)

       securityd <eeb8bd36f685306db25c302d7f3e18b4>          234              234                      (daemon)

             ubd <da941d158131359ab82559fdf8b99cb7>         1116             1116                      (daemon)

      DTMobileIS <0e7e02810e383e2c9ebc212d94b6044f>            0                0                      (daemon)

notification_pro <08df322fbe7739199f78852a511169ef>          229              229                      (daemon)

            afcd <3bd960d39c9f3972a10923db0e687b4a>          189              189                      (daemon)

filecoordination <28ca39773e933ed2aa92c117c661d056>          198              198                      (daemon)

       distnoted <699b8253736233b29180419f139e8c01>          165              165                      (daemon)

            apsd <5be27dc5ea5234319bc4b47380e42174>          436              436                      (daemon)

        networkd <49064febbe553338bd98051399022da4>          239              239                      (daemon)

      aggregated <c5a375854c3c31d59548ab53ea86d194>          125              125                      (daemon)

       fseventsd <3ea853cb95de3aa48972aa42637af69a>          395              395                      (daemon)

        BTServer <af0150d5085e326598edff072a23d146>          345              345                      (daemon)

         imagent <2b64c6111aa63b179a15afd6a76a6696>          521              521                      (daemon)

         configd <b6a4d70640b63e8f82e0e9f3d6ee2bb9>          599              599                      (daemon)

   fairplayd.J2a <16c2b90ca188332ca3ae87056352a2c9>          969              969                      (daemon)

       lockdownd <a123aa04ddf83a5fae8e5bc08f0b5771>          530              530                      (daemon)

          powerd <63673a83ac9c3cf98fdc75df8ba70fd0>          220              220                      (daemon)

   mDNSResponder <1e651badfb7033a68a73a667ec480a08>          356              356                      (daemon)

         keybagd <b9d6f4a61ac63fc997426fe03726c690>          180              180                      (daemon)

      CommCenter <cb877b4411ee3a348ec44c02ff3da38d>         1498             1498                      (daemon)

         notifyd <67a17b0c297e3785a9e09b8e72f3636a>          198              198                      (daemon)

**End**


#8

FYI: adding the chart as a subview in the constructor of the view doesn’t make any difference.


#9

Any new on this issue yet?


#10

Hi,

We are looking into the issue at the moment. Thanks for your patience.

Jan


#11

Hi Boo-Lee,

We managed to reproduce your issue last night using an iPad 3 and monotouch. We had an initial look and haven’t been able to see what is happening yet, but the problem only occurs with Xamarin.iOS on the iPad 3. We tried it on other devices and also build a native clone of your project and the problem does not appear.

We are continuing to investigate this and hope to get back to you with a solution soon.

Regards,
Chris


#12

Thank you Chris and Jan.

Fingers crossed …


#13

Hi Boo-lee,

We have managed to replicate your crash and it turns out it is not Monotouch specific. We suspect that the GL buffers are filling up as you are pre-allocating all of your charts when your application starts up.

The reason this crash isn’t seen on the simulator is because your computer has a lot more memory than the device. This crash isn’t seen on older devices when running your project either, as these devices do not have a retina screen, thus do not fill up their GL buffers as quickly. No matter what the device/system you are running your project on, it will always eventually get memory warnings after initialising too many charts.

What we recommend is to create your charts as and when you need them, rather than holding them all in memory at the same time. You could create your chart when your view appears and clear up your chart when your view disappears. I managed to stop the crash by putting the following in your ChartViewController:

ShinobiChart chart = null;
SChartDataSource ds = new ChartDataSource();

…


public override void ViewWillAppear (bool animated)
{
    base.ViewWillAppear (animated);
    if (chart == null) {
        chart = new ShinobiChart (View.Bounds);
        chart.DataSource = ds;
        View.AddSubview (chart);
    }
}

public override void ViewDidDisappear (bool animated)
{
    base.ViewDidDisappear (animated);
    if (chart != null) {
        chart.RemoveFromSuperview ();
        chart.Dispose ();
        chart = null;
    }
}

There are other ways you could manage your charts if you do not want to re-recreate your chart every time your view controller appears, such as cleaning them when you receive memory warning, adding the same chart to different subviews, or just switching out the data source and reloading the chart when a user clicks on a ‘tab’. This is this really is an object lifecycle issue, rather than a library bug.

I hope I have given you enough information to get you back on track with your development. If you have any other questions, please don’t hesitate to ask.

Thanks,
Jan


#14

Thank you for your time and the detailed explanation.

I tried applying your proposed strategy on my real world problem, but it doesn’t seem to work, I get the following error after the chart is set to null:

Selector invoked from objective-c on a managed object of type <my chart class derived from ShinobiChart> that has been GC’ed.

Apparently the code under the hood still references subviews even if they have been removed from their superview.

If I just remove the chart but keep it in memory, my app crashes on the real device because of memory warnings.


#15

Even when I completely reset my View in my ViewController, I still get the “Selector invoked …” message.  :cry:

Something unmanaged must still be referencing the chart.

So the “creating the chart” when needed strategy doesn’t seem to work either …


#16

I can send you the modified version of the project you uploaded for this thread if you like? (With my changes to stop the application crashing.) If you would like this, please send an email to info@shinobicontrols.com referencing this forum post, and I will send it right over. As for your other issue, it really sounds like more of a memory management / life cycle issue than a charts component issue.

The project I have created should help, so take a look at that and we will take it from there  :laughing:.

Thanks,
Jan 


#17

Hi Jan,

The other issue (Selector invoked … GC’ed) definitely had to do with the chart control itself.

But …

I managed to solve all issues!

My situation was a bit more complicated than my test project you downloaded:

  • All my views are hosted in a scrollview instead of a tabbarcontroller

  • The views (containing the chart) on the left and the right side must always be completely “preloaded” because when the user starts swipes left or right, the content of the neighbour view must be shown.

Solution:

  • When a view controller is no longer in the “view slot” (the current page and its neighbour page(s)), I set the view controller’s view to a dummy view (letting MonoTouch take care of GC’ing the old view). Simply removing the chart from the view using (RemoveFromSuperview) caused a native “selector… GC’ed” error.

  • When a view controller becomes part of the “view slot”, I set its view to a new (chart containing) view.

  • I had to use the ShinobiChart class directly. I first used a derived class but for some strange reason this also caused the dreaded “selector… GC’ed” error.

  • In my chart datasource method override SChartSeries GetSeries(ShinobiChart chart, int dataSeriesIndex) there was a statement "return ((MyChart)chart).CreateSeries();. It was implemented that way because I found this in one of the Xamarin.IOS projects in the Shinobi examples. This also caused a “selector…GC’ed” error when the chart was released from memory. When I let the datasource create the series directly, It all finally worked.

I’m not sure I understand it all completely, but I’m very glad the charts now work. Thank you very much for your advice and support!


#18

Hi Boo-lee,

Glad you managed to get it working. If you want to see your sample edited to contain chart creation / cleaning up then just send a quick email over to info@shinobicontrols.com.

Thanks,
Jan