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)?
  • Can you update the API Documentation of the toDegrees method of Class: Toybox::Position::Location to specify that the resultant array is an array of Doubles?


    I'm doing this as we speak. :) We're in the midst of a larger effort of strengthening our API docs, and I had already been working on the Position API documentation when this issue arose. We had previously stated that these methods return an Array, but never specified what types were in the Array. This will be addressed in the next major SDK release.
  • Former Member
    Former Member
    I think I may have been a bit hasty in my earlier post and underestimated the precision required for the exercise. My on-water testing today exhibited some lack of precision in the results which may be due to loss of precision by using Floats.
    I will explore the use of integers by using your suggestion of x / 180.0 * 0x80000000, but would appreciate a little fleshing out of the reasoning behind the factors.
    I followed the suggested link, but the reference links were broken, so I didn't get the full argument.


    The references aren't really important for that investigation.
    The first source is documentation of the IEEE floating point spec.
    The second is a calculator that gives the distance between latitudes and longitudes.
    The third I'm not sure. I think it gives the precision of floating point at different values.
    The last one is just lat/lon locations of the extreme points of the US they used for the test values.

    Floating point numbers have less precision after the decimal point the larger they get, so the worst case for longitude is at 180.00 degrees. The next smaller number that can be represented with single precision floating point is. 179.99998, which means you jump 0.00002 degrees of longitude at this point. At the equator, that means you would jump 0.00002/360 of the earth's circumference, which is 40,075 km, which is about 2.2 meters.

    Figuring out the exact error in different parts of the world is complicated because it depends on the floating point precision at that point, and size of the steps in latitude and longitude at that point. The link I provided computes the error at different points around the United States. Ultimately all you need to know is that using floating point is going to snap your positions to a grid that is on the order of 1m in spacing.

    I think your app will still be fine on handles if you store your latitudes and longitudes in double precision, which is probably easier than converting to fixed point. You'd just need to make sure you convert your derived values to float because they are unlikely to need the double precision.
  • The epidemic of Doubles...continued.

    You'd just need to make sure you convert your derived values to float because they are unlikely to need the double precision.

    Going through my code, many of the values are derived from lat/lon using Module: Toybox::Math.atan2 which according to the API docs, returns Float:
    #atan2(y, x) &#8658; Float
    Use atan2() to get the arc tangent of y/x in radians.

    Wrong!
    If the arguments are Doubles, they return Doubles!
    Is this a bug in the documentation or the software?
    (and if the arguments are integers, it returns a zero valued float!)
  • Wow, I never even noticed they introduced atan2(), I'm still using the version I wrote using atan() back in the pre 1.3.0 days. I guess I have some cleanup to do.
  • One of the advantages of being a newby. I would have been very disappointed if it didn't have an atan2. But it still obviously needs work.
  • You are correct! This is a documentation issue that we're addressing as part of a larger documentation effort currently taking place.

    Math.atan2() accepts any numeric Monkey C format, but will return either a Float or a Double. It maps like this:

    [TABLE="class: grid, width: 500"]
    [TR]
    [TD]Input[/TD]
    [TD]Output[/TD]
    [/TR]
    [TR]
    [TD]Number (int)[/TD]
    [TD]Float[/TD]
    [/TR]
    [TR]
    [TD]Float[/TD]
    [TD]Float[/TD]
    [/TR]
    [TR]
    [TD]Long[/TD]
    [TD]Double[/TD]
    [/TR]
    [TR]
    [TD]Double[/TD]
    [TD]Double[/TD]
    [/TR]
    [/TABLE]

    You should not be receiving a zero-value float from two Number (int) inputs, however. In fact, I'm not able to reproduce that. For example, Math.atan2(1, 1) == 0.785398, or 45 degrees (as you'd expect).

    Going through my code, many of the values are derived from lat/lon using Module: Toybox::Math.atan2 which according to the API docs, returns Float:
    Wrong!
    If the arguments are Doubles, they return Doubles!
    Is this a bug in the documentation or the software?
    (and if the arguments are integers, it returns a zero valued float!)
  • Yes, you're right, I think I was dividing a Number by a bigger Number and getting 0
  • I'm working to reduce the number of objects by storing and array of GPS coordinates (latitude, longitude) as integer units I call "billis, where degree to billi = 0x80000000/180.

    Now that's all working fine, but when I convert back as necessary to do some trig, I need the value in radians, so I have a factor billi2radians = Math.PI/0x80000000.
    The trouble is, that gives me a nonsensical result:

    See next post ("Access Denied")
  • (and then I have to wait 120 sec's before posting the remainder!)
    var billi2rads = 3.14159265d/0x80000000;
    System.println("billi2rads:"+billi2rads.format("%.20f"));

    returns
    billi2rads:-0.00000000146291807760

    Note the -ve sign.
  • That code behaves exactly as I'd expect.

    The issue is that you are dividing a positive value by a negative value... the constant 0x8000000 is a 32-bit signed integral (Lang.Number) with the value -2147483648 (one beyond the largest representable value). Are you sure you want to use that value instead of 0x7FFFFFFF? If you do, the simplest option is to use a floating-point constant. You'll probably want to use a double because the result is going to be very tiny and you will probably want the precision.

    // 1.462918079267256e-9
    var billi2rads = Math.PI / 2147483648.0d;


    Travis