Too Many Objects Error

My app works perfectly on the watch in my "Sim" mode (for development/testing) when replaying an old yacht race, but crashes with "Too Many Objects Error" when running with live data from the GPS.
It looks to me like Position.enableLocationEvents(Position.LOCATION_CONTINUOUS, method(:GPSData)); is generating objects, but that doesn't make any sense really.
In my "Sim" mode, I'm calling my app's main processing function with data that I'm retrieving from my web site.
In live mode, I'm calling it with data from the Position.enableLocationEvents callback.
Other than that the two modes are identical.
In "Sim" mode. the app runs for an entire race of over 2 hours.
In Live mode, it crashes after around two minutes.
ERROR: Too Many Objects Error
DETAILS: Failed invoking <symbol>
STORE_ID: 00000000000000000000000000000000
CALLSTACK:
144)*Failed while writing stack trace*

I'm monitoring memory each callback cycle, and memory usage remains static up to the crash.
Memory Total:125272 Used:101208 Free:24056


Sure, I'm pushing the watch, running with around 24Kb free, but with no way to monitor object usage, I'm in a big hole.
The issue has started since I added the latest feature which has increased memory usage by around 30Kb.
Any thoughts (before I slit my throat)?
  • Former Member
    Former Member
    I am struggling with concepts such as "reference counting". Is it possible that there's a latency in the destruction of the objects?

    I'm improving the up-time of my app by artificially inserting delays in my code with
    • adding a 500 ms timer delay between receiving the data and processing or
    • inserting System.println debug lines in my long data processing function
    • breaking up a single long function into multiple short ones

    Which seems to support that theory.



    Could you provide an example of a circular reference in this context please?


    There is no latency in object destruction.

    Here is a very simple example.
    function example() {
    var myVar = new [5]; //a 5 element array is created here. It has a reference count of 1
    var anotherVar = myVar; //Now the array is referenced twice it has a reference count of 2

    myVar = null; //myVar no longer references the array. It has a reference count of 1

    return;
    } // anotherVar has gone out of scope and no longer references the array.
    //It's reference count is 0. It is destroyed immediately.



    A circular reference is when two objects hold reference to each other. This is fine up until the point where all other references are gone, in which case, your program has no way of freeing the memory.

    Here is a simple circular reference error example:

    function example2() {
    var arrayA = new [5]; //a 5 element array is created here.
    //It is referenced by 'var arrayA' and has a reference count of 1
    var arrayB = new[5]; //another 5 element array is created here. It has a reference count of 1
    //It is referenced by 'var arrayB' and has a reference count of 1

    arrayA[0] = arrayB; //We've inserted arrayB into arrayA.
    //It now has two references ('var arrayB' & arrayA[0]) and has a reference count of 2.
    arrayB[0] = arrayA; //We've inserted arrayA into arrayB.
    //It now has two references ('var arrayA' & arrayB[0]) and has a reference count of 2.

    return;
    } // arrayA and arrayB have gone out of scope and no longer reference the array objects.
    // Each reference count is reduced by 1 (to 1), but both are still non-0 because they reference each other.
    // Neither array is destroyed, but the application no longer has any references to the objects and cannot
    // Break the link between the two arrays. The memory and object handles used by these are leaked for
    // the remainder of the application life cycle.
  • Hey Brandon, thanks for that, there's nothing like a simple example to demonstrate a concept.

    So, if there's no latency in destroying unused referenced objects, I have to conclude that Position.enableLocationEvents(Position.LOCATION_CONTINUOUS, method(:GPSData)) is leaving some referenced objects.

    My reasoning is that when I run my code with my Sim code generating the positionInfo it runs fine, but it crashes with "Too Many Objects" when I run with Position.enableLocationEvents generating positionInfo.

    Is there any way to test this theory, by counting the number of objects before and after?
  • I use

    Position.enableLocationEvents(Position.LOCATION_CONTINUOUS, method(:onPosition));

    in many things, and I know they run on a real watch for hours upon hours, with no out of object errors, so you really need to look at your own code.

    This is actually a basic thing for any watch-app that uses GPS, and it's use is quite common. If you want, download either my "Hike2" or "Simple Walk" app from the store. Both do this. Start the app, and when it get's a good GPS fix, you are told to press start. Press start and then let it run for as long as you want. They both also save the lat/lon every minute so a chart of the route is displayed on one of the screens, so you can see it's actually getting on-going GPS data. Both also have a screen where you can see lat/lon updating every second.

    Trust me, there's something else going on...... Maybe with how you do your simulated data or something about timing differences, as with real GPS data, your callback is consistently called every second. (I'm still wondering about the timer thing where you're delays things 500ms at times. Are you doing that due to problems with the watchdog timer or something?)
  • I'm still wondering about the timer thing where you're delays things 500ms at times

    Like I said, I put it there to exercise the GC. I now learn the GC doesn't exist I have removed it and the app still crashes in live mode with "Too Many Objects" error.

    All your suggestions would be sound except for the fact that they relate to code which is working fine in my simulate mode which operates at 1, 2 or 4Hz on exactly the same type of data.

    One thought that comes to mind is that the "Too Many Objects" may be a red herring and it's something else altogether, but I really don't want to speculate on that!
  • Like I said, try one of my apps. You can see for yourself that what you see has nothing to do with the callback for GPS data... It's something with your code. Any chance of a circular reference as Brian demonstrated?
  • Do you see the problem running in "Real" mode if you run it in the connectiq watch simulator playing back a fit file to give you the GPS data you need?

    If so you may be able to see if you are leaking objects by using the "View Memory" option.
  • Let me summarize the test results:
    Platform: CIQ SimulatorFIT replay
    No Crash

    My Sim mode
    No Crash

    GPS Data
    Not Available (No GPS on the PC)

    Platform: Watch (VA-HR)FIT replay
    Not Available (Only available in CIQ Sim)

    My Sim mode
    No Crash

    GPS Data
    Crash



    Looks to me like a feature of the GPS?
  • Former Member
    Former Member
    Is there any chance you could break this issue down to a basic sample that demonstrates the problem and send it to [email][email protected][/email]?

    It is possible there is a memory leak in the VM that you are exposing on devices, but we probably need an example to investigate with since there aren't any other apps we know of that are leaking handles from the positioning callback.

    It is rather strange that you are running out of handles in this way without seeing a steady increase in memory usage. If you were leaking objects, you should see this drift up at some rate even if they are very small.
  • I'm going to work on breaking this down over the weekend...
  • It is rather strange that you are running out of handles in this way without seeing a steady increase in memory usage. If you were leaking objects, you should see this drift up at some rate even if they are very small.

    And I can confirm that I'm not seeing a steady increase in memory usage. It's a flat line at around 24Kb free (29 on the CIQ Simulator).