For the last 1-2 weeks, a few watch faces have been crashing on my Epix 2 after it's been running for more than one day. They all crash at the same time, and the only way to get them to load again is to restart the device. I've generally ruled out a memory leak.
The source of the problem seems to be use of Graphics.createBufferedBitmap. This call is "randomly" working fine and randomly causing an out-of-memory issue. ("Randomly" is in quotes because it works fine when the device is freshly started, but after some unknown time, all watch faces making this call fail - including ones I made and one from the store).
Here's what I know:
- The 3 watch faces I made (all still in private beta):
- Generally use 70% - 80% memory (on device) - I added a gauge to see it realtime on all my faces
- Memory usage remains constant according to this gauge - there's no memory leak / change in memory over multiple days of consistent use of the same watch face
- 1 of the watch faces worked consistently well with no crashes (memory-related or otherwise) from Dec 1, 2022 through the end of December. The other 2 faces are brand new as of the last 1-2 weeks since the new year.
- All my faces use BufferedBitmap to enable 1hz updating (with a second indicator). For each minute, I draw to the BufferedBitmap and then draw that to the screen. Then, between minutes, if the device is awake, I'll draw the background minute via the BufferedBitmap. Then I'll also draw the second indicator directly to the DC over the top. This allows me to keep the onUpdate call for each second to about 6 milliseconds of execution time.
- All my watch faces use exactly 1 BufferedBitmap set to the full dimensions of the DC. I use anti-aliasing, so I cannot use a pallet. I also do not specify a color depth. This BufferedBitmap is stored in a variable inside the class that extends WatchUi.WatchFace.
- All watch faces (ones I made + one I didn't):
- Work fine for the first day or so
- They all crash together at the same time / they all work fine when the device is restarted
- The crash generally happens when the watch face goes from not being displayed to being displayed again (e.g. after the Morning Report or after exiting an activity)
The watch face that's crashing that I didn't make is "Analog Switch"
About a week ago, I began some research into this issue by looking at the error logs on the device and tracking it back to the function where the Graphics.createBufferedBitmap call happens.
To test my hypothesis that this is a system-level issue (and not something related to the design of the watch faces), I created a minimum reproducible watch face (I call it MemoryX for "Memory Explorer"). To create it, I took the new Watch Face project and made very slight modifications to make it use a BufferedBitmap to draw the time to the screen (based on a setting). Once the watch goes into the mode where all the watch faces crash, MemoryX loads fine if I turn off the use of the BufferedBitmap. But if I toggle the setting to make it use the BufferedBitmap, it crashes, too. When using the BufferedBitmap, MemoryX only used 7.3/123.9kB on the simulator. But this crashes on the device.
Questions:
- Is anyone else experiencing this or something related? I noticed Gavriel reported another memory issue recently.
- Why would they all crash at the same time? Even if one of the faces had an out-of-memory issue, shouldn't that be isolated?
- It's odd that this happens "randomly" after some time -- can anyone think of something I need to be cleaning up in onHide/onShow that I'm not?
I can't seem to post formatted code (it's telling me I'm blocked). And I know I can't post images, either. But here's the code (unformatted) inside the onUpdate function. I'll try to post it more clearly in a comment below:
}