Cost of using custom fonts with layouts is unexpectedly high

The application I'm working on uses layouts and custom fonts. I've discovered that for every <label> element that uses my custom font, 3091 bytes of memory on the device is being used. I wrote a test application to collect data, and this is what I came up with.

Fields *1 *2 Usage
4 4 0 12730
4 3 1 15821
4 2 2 18912
4 1 3 22003
4 0 4 25094

*1 = fields using Gfx.FONT_XTINY
*2 = fields using Rez.Fonts.Consolas_12px



The summary is that for every label that I switch to use my custom font (from Gfx.FONT_TINY), my application incurs a 3091 byte penalty. I'm curious if this is expected behavior or not? It seems that since font data is static it could be shared, the cost should be constant (after the first field) and not linear.

I'm currently displaying 28 labels on one of my views, and the memory usage for the layout data alone is over the 75KB limit. It appears that my choices are to use a built-in font and display less data on a page or to use a custom font and render my text directly using dc.drawText() (and probably caching the font myself).
  • I'm guessing that the issue is that each label is effectively calling Ui.loadResource() to load the font data, and that the resource system isn't doing any caching. It seems that the layout loader could maintain a local cache of fonts that is used when loading a layout. This would reduce the number of Ui.loadResource() calls and the memory usage of the application.

    In the meantime, I managed to work around the problem with the following.

    // a monostate that keeps resources in memory until they need to be unloaded. this
    // could be modified to intelligently manage resources to keep memory use under a
    // predefined limit.
    class ResourceCache
    {
    static var cache;

    static function register(resource) {
    if (cache == null) {
    cache = {};
    }

    var cached = cache.get(resource);
    if (cached == null) {
    cached = Ui.loadResource(resource);
    cache.put(resource, cached);
    }

    return cached;
    }

    static function deregister(resource) {
    if (cache != null) {
    cache.remove(resource);
    }
    }
    }


    Then I use it like this...

    function onLayout(dc) {
    layout = Rez.Layouts.Details(dc);

    var font = ResourceCache.register(Rez.Fonts.Consolas_12px);
    for (var i = 0; i < layout.size(); ++i) {
    layout.setFont(font);
    }

    setLayout(layout);
    }
    [/code]

    Since my application uses the font extensively, there is no reason for me to ever unload it. As a result, the memory usage of my application goes from ~150KB to ~60.
  • Hi Travis, thanks for the report. I've filed a task to share the fonts instead of each label object using its own.