CoronaCards WP8 Memory problem

Hi, I’m porting a corona game to windows phone, and I have now trouble around memory usage.

I’m getting the same problem as this post:

https://forums.coronalabs.com/topic/52167-notes-on-porting-to-wp8/

ie, our app get OutOfMemoryException, some images are replaced by others and the app hangs up or crashes.

My device is Lumia 640 and the memory can be allocated up to 380MB.

I’m working with reducing memory usage on the app, but it seems that the memory is still leaked even if the objects are destroyed with removeSelf() and nilled.

I made a test program to make sure this, and here’s the result:

Test 1: executing display.newText() 100 times with 100 characters

result:

At Start(bytes): Mem: 36114432 Peek: 36671488

After created objects: Mem: 301129728 Peak: 355057664

After removed the objects and executed GC.correct() on c#: Mem: 295649280 Peak: 355057664

Test 2:  executing display.newImage() 100 times with world.jpg

Result:

At Start(bytes): Mem: 36048896 Peak: 36589568

After created objects: Mem: 42893312 Peak: 43806720

After removed the objects and executed GC.correct() on c#: Mem: 43290624 Peak: 44224512

Test 3:  executing display.newImage() 100 times with 100 x 100 rectangle

Result:

At Start(bytes): Mem: 36241408 Peak: 36802560

After created objects: Mem: 42360832 Peak: 43274240

After removed the objects and executed GC.correct() on c#: Mem: 43290624 Peak: 44220416

It seems that removeSelf() and obj = nil does not help on Windows phone.

Is it a bug on coronacards, or is it something wrong with my code?

And I’d like to know the way to avoid such memory leak or force to free memories on WP, if someone knows.

Here’s the test code:

main.lua

-- -- Abstract: Hello World sample app. -- -- Version: 1.2 -- -- Sample code is MIT licensed -- Copyright (C) 2014 Corona Labs Inc. All Rights Reserved. -- -- Supports Graphics 2.0 ------------------------------------------------------------ -------------- -- Variables local background = display.newImage( "world.jpg", display.contentCenterX, display.contentCenterY ) local myObj = {} local i = 0 local txt = "abcdefghijklmnopqrstuvwxy" txt = txt .. txt ..txt ..txt -- 100 characters print("Length",#txt) local mode = 1 -- 1:display.newText, 2:display.newImage, 3:display.newRect local cycle = 100 -------------- -- Functions local function getMem(msg) local req = { name = "requestingMem", } local result = Runtime:dispatchEvent( req ) print( msg, tostring(result) ) end local function finish(ev) getMem("After GC") end local function wpgc(ev) local req = { name = "requestingMem", } local result = Runtime:dispatchEvent( req ) timer.performWithDelay( 3000, finish ) end local function mkTxt() print("MODE","txt") for i = 1, cycle do myObj[i] = display.newText(txt, display.contentCenterX, display.contentCenterY, native.systemFont, 20 ) myObj[i]:setFillColor(1.0, 0.5, 0.3) end end local function mkImg() print("MODE","img") for i = 1, cycle do myObj[i] = display.newImage("world.jpg",display.contentCenterX, display.contentWidth / 4 + (i)) end end local function mkRect() print("MODE","rect") for i = 1, cycle do myObj[i] = display.newRect(display.contentCenterX, display.contentWidth / 4 + (i),100,100) myObj[i]:setFillColor( 1.0, 0.4, 0.4 ) end end local function free(ev) getMem("Objects created") print("Removing Objects...") for i = 1, cycle do if myObj[i] then myObj[i]:removeSelf() myObj[i] = nil end end timer.performWithDelay( 3000, wpgc ) end -------------- -- Main Logic getMem("Start"); if mode == 1 then mkTxt() end if mode == 2 then mkImg() end if mode == 3 then mkRect() end timer.performWithDelay( 3000, free ) -- END 

MainPage.xaml.cs

using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using System.Windows.Threading; using System.IO; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using Bay.Resources; using Windows.Storage; using Windows.Storage.Streams; using System.Windows.Media.Imaging; using System.Diagnostics; namespace Bay { public partial class MainPage : PhoneApplicationPage { public MainPage() { // Initialize this page's components that were set up via the UI designer. InitializeComponent(); // Set up Corona to automatically start up when the control's Loaded event has been raised. // Note: By default, Corona will run the "main.lua" file in the "Assets\Corona" directory. // You can change the defaults via the CoronaPanel's AutoLaunchSettings property. fCoronaPanel.AutoLaunchEnabled = true; #if false // Set up the CoronaPanel control to render fullscreen via the DrawingSurfaceBackgroundGrid control. // This significantly improves the framerate and is the only means of achieving 60 FPS. fCoronaPanel.BackgroundRenderingEnabled = true; fDrawingSurfaceBackgroundGrid.SetBackgroundContentProvider(fCoronaPanel.BackgroundContentProvider); fDrawingSurfaceBackgroundGrid.SetBackgroundManipulationHandler(fCoronaPanel.BackgroundManipulationHandler); #endif // Add a Corona event handler which detects when the Corona project has been loaded, but not started yet. fCoronaPanel.Runtime.Loaded += OnCoronaRuntimeLoaded; } /// \<summary\> /// Called when a new CoronaRuntimeEnvironment has been created/loaded, /// but before the "main.lua" has been executed. /// \</summary\> /// \<param name="sender"\>The CoronaRuntime object that raised this event.\</param\> /// \<param name="e"\>Event arguments providing the CoronaRuntimeEnvironment that has been created/loaded.\</param\> private void OnCoronaRuntimeLoaded(object sender, CoronaLabs.Corona.WinRT.CoronaRuntimeEventArgs e) { e.CoronaRuntimeEnvironment.AddEventListener("requestingMem", OnRequestingMem); e.CoronaRuntimeEnvironment.AddEventListener("requestingGC", OnRequestingGC); } /// \<summary\>Called when Corona runtime event "requestingSS" has been dispatched.\</summary\> /// \<param name="sender"\>The CoronaRuntimeEnvironment that dispatched the event.\</param\> /// \<param name="e"\>Provides the Lua event table's fields/properties.\</param\> // Returns Current App Memory to Lua private CoronaLabs.Corona.WinRT.ICoronaBoxedData OnRequestingMem( CoronaLabs.Corona.WinRT.CoronaRuntimeEnvironment sender, CoronaLabs.Corona.WinRT.CoronaLuaEventArgs e) { string mem = Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage.ToString(); string maxmem = Microsoft.Phone.Info.DeviceStatus.ApplicationPeakMemoryUsage.ToString(); MemoryTextBlock.Text = mem; PeakMemoryTextBlock.Text = maxmem; return CoronaLabs.Corona.WinRT.CoronaBoxedString.From("Mem: " + mem + " Max: " + maxmem); } // Execute GC private CoronaLabs.Corona.WinRT.ICoronaBoxedData OnRequestingGC( CoronaLabs.Corona.WinRT.CoronaRuntimeEnvironment sender, CoronaLabs.Corona.WinRT.CoronaLuaEventArgs e) { GC.Collect(); string mem = Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage.ToString(); string maxmem = Microsoft.Phone.Info.DeviceStatus.ApplicationPeakMemoryUsage.ToString(); MemoryTextBlock.Text = mem; PeakMemoryTextBlock.Text = maxmem; return CoronaLabs.Corona.WinRT.CoronaBoxedString.From("Mem: " + mem + " Max: " + maxmem); } } } &nbsp;

 Thanks.

Sorry, I took a mistake about GC on Main.lua line 44. here is the fix:

- name = "requestingMem", + name = "requestingGC",

and added collectgaebage also on line 46:

+ collectgarbage( "collect" )

here I show the new result. I could reduce memory usage but still a lot of memories are used…

Test 1: executing display.newText() 100 times with 100 characters

result:

At Start(bytes):Mem: 22159360 Peak: 22745088

After created objects: Mem: 284180480 Peak: 339853312

After removed the objects and executed GC.correct() on c#: Mem: 154644480 Peak: 339853312

 

Test 2:  executing display.newImage() 100 times with world.jpg

Result:

At Start(bytes):Mem: 22151168 Peak: 22732800

After created objects: Mem: 27402240 Peak: 27418624

After removed the objects and executed GC.correct() on c#: Mem: 27447296 Peak: 27467776

 

Test 3:  executing display.newImage() 100 times with 100 x 100 rectangle

Result:

At Start(bytes): Mem: 22134784 Peak: 22720512

After created objects: Mem: 27271168 Peak: 27287552

After removed the objects and executed GC.correct() on c#: Mem: 27475968 Peak: 27475968

In this test, I use Lumia 640 XL and there are less installed Apps than the machine in the post before, so the initial memory usage are relatively low.

Thanks.

I’m not convinced this is a memory leak.

The application memory usage that you are fetching doesn’t indicate how much memory the app is actively using.  That’s the current heap size.  When objects/data gets released from memory, the native C/C++ runtime’s heap manager and .NET garbage collector tend to hold on to that memory so that it can re-used later for best performance.  Android and iOS work this way as well.  Pretty much all platforms do.  And calling GC.collect() does not necessarily force the garbage collector to reduce the heap size as well, because that’s up to the garbage collector to decide (but it’ll usually reduce it if the memory reduction is significant enough).

 A better test would be to add/remove display objects on every frame to see if there is *runaway* memory usage.  For example, display the current via display.newText() on every enterFrame (it’s a huge performance hit, but would be a good memory test).  What this will prove is that the WP8 native memory manager is correctly re-using freed memory in the heap for new images/textures.  I’m quite positive this will work fine.

A user of our app has also reported that the incorrect images are being displayed on his Lumia 635. In this case it is the bitmap font texture being used instead of several other textures. Is there a solution to this?

>> A user of our app has also reported that the incorrect images are being displayed on his Lumia 635.

We’ve never been able to reproduce this.  However, we have heard of rare cases where this happens to some Corona developers in Microsoft’s WP8 emulator (ie: the emulator you launch from Visual Studio).  Such as what was mentioned here…

   https://forums.coronalabs.com/topic/49582-setting-the-scale-of-an-image-fill-of-shapeobject-seems-to-have-no-effect/?p=258065

We later discovered that there was a known Microsoft C++ compiler bug that *might* have caused this specific issue randomly on some people.  As in the compiler was not compiling certain things we’ve coded it to do.  We’ve worked around that compiler bug in daily build #2643.  That *should* theoretically fix that specific issue, but since we’ve never been able to reproduce it on our end, we don’t know if it will.

   https://connect.microsoft.com/VisualStudio/feedback/details/739798

You should also double check that you are using the newest update/path of Visual Studio.  The first version of Visual Studio 2013 has some compiler bugs that nailed us on the Win32 desktop that was solved by updating to the newest version of Visual Studio 2013, which is currently “Update 5”.  I’m not sure if these same issues affect WP8 compiled apps, but I recommend that you update your Visual Studio to get Microsoft newest fixes/patches just in case.

Thank you for your reply and great hints!

I made another test that Joshua recommended:

local tobj = nil function onEnterFrame(e) if tobj == nil then tobj = display.newText(txt, display.contentCenterX, display.contentCenterY, native.systemFont, 20) tobj:setFillColor(1.0, 0.5, 0.3) else tobj:removeSelf() tobj = nil end end Runtime:addEventListener("enterFrame", onEnterFrame)

in this way, I could see that the memory is freed and app heap size was reduced successfully.

And I made also an other test to simulate more complicated case.

In this program, text objects are inserted to a group 100 times and then deletes both text objects and the group.

The result is that the app heap size remains about 140MB after 10 cycles of the test in spite ob all objects should have been removed.

Do I have anything wrong with removing objects?

I really appreciate your help!

local grp = nil local tobj = nil local n = 0 local cycle = 0 function onEnterFrame(e) if grp == nil then grp = display.newGroup() tobj = {} end tobj[#tobj] = display.newText(txt, display.contentCenterX, display.contentCenterY, native.systemFont, 20) tobj[#tobj]:setFillColor(1.0, 0.5, 0.3) grp:insert(tobj[#tobj]) if n == 100 then print("Delete group", cycle) local c = #tobj for i = 0, c do if not tobj[i] == nil then tobj[i]:removeSelf() tobj[i] = nil end end grp:removeSelf() grp = nil n = 0 tobj = nil cycle = cycle + 1 if cycle \> 10 then Runtime:removeEventListener("enterFrame", onEnterFrame) end end n = n + 1 end Runtime:addEventListener("enterFrame", onEnterFrame)

Doing a removeSelf() and nil’ing out the object is definitely the right thing to do.

Regarding keeping your memory size low, the key thing to remember is that the size of the PNG or JPEG files you are using doesn’t matter.  When you load an image via display.newImage(), display.newImageSheet(), etc… Corona must decode the image to a 32-bit color uncompressed bitmap in order to submit it as a texture to the GPU.  That’s 4 bytes per pixel, which also means the amount of memory a decoded image takes in memory is predictable.  Here’s the formula to make it a little more clear…

   totalMemoryInBytes = pixelWidth * pixelHeight * 4

Masks and text objects are loaded as 8-bit grayscale bitmaps.  So, they’re 1 byte per pixel, making them significantly cheaper than image objects.

Another useful tip is in regards to audio.  If you have any large audio files that you use for music, then you may want to use our audio.loadStream() API instead of audio.loadSound().  The audio.loadSound() function will decode the entire audio file to memory, which is really only suitable for short sound effects because you can play them quickly with little to no latency.  audio.loadStream() works kind of like Internet audio streaming, except it streams from file, loading small chunks (ie: audio frames) from file into memory and is intended for low-memory situations such as this.

Hi,

Thank you for your reply and tips. We’ve never optimized audio features so It’s worth for us to take a look into our sound functions.

Btw I found that the memory usage rises significantly when we use external font.

For example, when I added Osaka-mono font to the project of the first example of my latest post, and changed ‘native.systemfont’ to “OsakaMono.ttf#OsakaMono”, the heap size raised to 168MB after 100 cycles and could not be freed.

Is this behavior correct?

In our app, memory problem was almost solved when I switched the external font to system font. 

That’s interesting.  We’re actually loading fonts via Microsoft’s Silverlight because that’s our only native option on Windows Phone 8.0.  So, we’re at Silverlight’s mercy on when the font gets freed from memory, or, perhaps Silverlight keeps it cached for the lifetime of the app?  I really don’t know.  I’ve seen a similar question on Microsoft’s forum (link below) which might suggest Silverlight keeps the font cached.

   https://social.msdn.microsoft.com/Forums/silverlight/en-US/a53752fd-5aa3-4e2e-b9c4-1dc2ca3ce973/memory-leak-with-embedded-font?forum=silverlightnet

I remember testing embedded fonts several times before.  I don’t recall any memory leaks happening.  The issue you are seeing here is that its a big jump in memory usage when using embedded fonts, right?

Oh and one more thing.  You do have the option to use the system fonts that are installed on WP8 as well.  Microsoft documents the fonts available via the link below.  I’m thinking that since the default system font that is already installed and preloaded into memory isn’t taking much memory from your app (its memory usage might not be counted against your app’s memory usage), then the other system fonts won’t either.  Might be a nice option if you’re trying to distinguish different text using different fonts, although I suspect you’re using an embedded font so that your text object size is reasonably consistent between platforms.  In any case, it might be worth a go.

   https://msdn.microsoft.com/en-us/library/windows/apps/hh202920(v=vs.105).aspx

Thank you for your suggestion.

It seems that the more letters a font file contains, the more memory is consumed.

I did further test with other fonts that are installed in Windows 10: Vedana and YU Gothic.

I copied these files to project folder and loaded from corona as embedded fonts.

Here are the definitions.

– YU Gothic

local font = “YuGothic.ttf#Yu Gothic”

– Verdana

local font = “verdana.ttf#Verdana”

When I used YU Gothic, the memory usage raised to 299MB after 100 cycle show and remove test.

For Verdana, the result was 70 MB with the same test.

The difference of these fonts is as below:

YU Gothic … Contains both Japanese and Western letters, 4,721 KB

Verdana … Contains only Western letters, 235KB

In my conclusion, the apps in English will not be affected so much by the memory problem with font because they have only 26 letters,

but if you consider localize internationally with embedded international fonts, the app will be affected.

Our app shows text messages many times to tell the stories and affected by this problem well, so I’m now considering to use system font that you are recommending.

However, I also hope that you find any possibility to make the situation better in future, because the system fonts are not so cool :frowning:

Well, it would make sense that a font that supports Asian characters would take up more memory than a font that only supports Western languages.  There are a lot more glyphs for the system to cache.

And yes, the larger the text and the more characters it has, the more memory the text object will take in memory.  Text objects are really 8-bit grayscale bitmaps/textures.  Here is how it works.  When you create a text object via display.newText() or update an existing text object’s text, Corona must create a new bitmap in RAM, have the operating system draw the text to that bitmap, and then submit that bitmap to the GPU as a texture.  The bitmap/texture we create will be set to the pixel width/height needed to fit the text you want, which means larger font sizes and more text means a bigger bitmaps and more memory.  This is how it works on all platforms (Android, iOS, Mac, Windows, and WP8).  It’s actually an expensive process on all platforms and will have a performance hit if you update text frequently, such on every enterFrame.

For frequently updated text or to reduce memory usage, it is usually best to use a bitmap font library instead.  How a bitmap font works is that you’ll have a single image file containing all of the characters needed for your text (ie: a sprite sheet).  Only this one bitmap needs to be submitted to the GPU and then the bitmap font library will assembly the character/sprites to form the text you want.  This is a very fast and efficient way of doing it and is a commonly used technique by AAA games.  However, the bitmap font technique is really only suitable for text that’s under your control because you have to guarantee that all characters you need in your text are contained in your imagesheet.  For example, it wouldn’t work well if the text came from the Internet such as Facebook or Twitter because then the odds are high that the characters you scraped from the Internet may not be in your imagesheet.

Sorry, I took a mistake about GC on Main.lua line 44. here is the fix:

- name = "requestingMem", + name = "requestingGC",

and added collectgaebage also on line 46:

+ collectgarbage( "collect" )

here I show the new result. I could reduce memory usage but still a lot of memories are used…

Test 1: executing display.newText() 100 times with 100 characters

result:

At Start(bytes):Mem: 22159360 Peak: 22745088

After created objects: Mem: 284180480 Peak: 339853312

After removed the objects and executed GC.correct() on c#: Mem: 154644480 Peak: 339853312

 

Test 2:  executing display.newImage() 100 times with world.jpg

Result:

At Start(bytes):Mem: 22151168 Peak: 22732800

After created objects: Mem: 27402240 Peak: 27418624

After removed the objects and executed GC.correct() on c#: Mem: 27447296 Peak: 27467776

 

Test 3:  executing display.newImage() 100 times with 100 x 100 rectangle

Result:

At Start(bytes): Mem: 22134784 Peak: 22720512

After created objects: Mem: 27271168 Peak: 27287552

After removed the objects and executed GC.correct() on c#: Mem: 27475968 Peak: 27475968

In this test, I use Lumia 640 XL and there are less installed Apps than the machine in the post before, so the initial memory usage are relatively low.

Thanks.

I’m not convinced this is a memory leak.

The application memory usage that you are fetching doesn’t indicate how much memory the app is actively using.  That’s the current heap size.  When objects/data gets released from memory, the native C/C++ runtime’s heap manager and .NET garbage collector tend to hold on to that memory so that it can re-used later for best performance.  Android and iOS work this way as well.  Pretty much all platforms do.  And calling GC.collect() does not necessarily force the garbage collector to reduce the heap size as well, because that’s up to the garbage collector to decide (but it’ll usually reduce it if the memory reduction is significant enough).

 A better test would be to add/remove display objects on every frame to see if there is *runaway* memory usage.  For example, display the current via display.newText() on every enterFrame (it’s a huge performance hit, but would be a good memory test).  What this will prove is that the WP8 native memory manager is correctly re-using freed memory in the heap for new images/textures.  I’m quite positive this will work fine.

A user of our app has also reported that the incorrect images are being displayed on his Lumia 635. In this case it is the bitmap font texture being used instead of several other textures. Is there a solution to this?

>> A user of our app has also reported that the incorrect images are being displayed on his Lumia 635.

We’ve never been able to reproduce this.  However, we have heard of rare cases where this happens to some Corona developers in Microsoft’s WP8 emulator (ie: the emulator you launch from Visual Studio).  Such as what was mentioned here…

   https://forums.coronalabs.com/topic/49582-setting-the-scale-of-an-image-fill-of-shapeobject-seems-to-have-no-effect/?p=258065

We later discovered that there was a known Microsoft C++ compiler bug that *might* have caused this specific issue randomly on some people.  As in the compiler was not compiling certain things we’ve coded it to do.  We’ve worked around that compiler bug in daily build #2643.  That *should* theoretically fix that specific issue, but since we’ve never been able to reproduce it on our end, we don’t know if it will.

   https://connect.microsoft.com/VisualStudio/feedback/details/739798

You should also double check that you are using the newest update/path of Visual Studio.  The first version of Visual Studio 2013 has some compiler bugs that nailed us on the Win32 desktop that was solved by updating to the newest version of Visual Studio 2013, which is currently “Update 5”.  I’m not sure if these same issues affect WP8 compiled apps, but I recommend that you update your Visual Studio to get Microsoft newest fixes/patches just in case.

Thank you for your reply and great hints!

I made another test that Joshua recommended:

local tobj = nil function onEnterFrame(e) if tobj == nil then tobj = display.newText(txt, display.contentCenterX, display.contentCenterY, native.systemFont, 20) tobj:setFillColor(1.0, 0.5, 0.3) else tobj:removeSelf() tobj = nil end end Runtime:addEventListener("enterFrame", onEnterFrame)

in this way, I could see that the memory is freed and app heap size was reduced successfully.

And I made also an other test to simulate more complicated case.

In this program, text objects are inserted to a group 100 times and then deletes both text objects and the group.

The result is that the app heap size remains about 140MB after 10 cycles of the test in spite ob all objects should have been removed.

Do I have anything wrong with removing objects?

I really appreciate your help!

local grp = nil local tobj = nil local n = 0 local cycle = 0 function onEnterFrame(e) if grp == nil then grp = display.newGroup() tobj = {} end tobj[#tobj] = display.newText(txt, display.contentCenterX, display.contentCenterY, native.systemFont, 20) tobj[#tobj]:setFillColor(1.0, 0.5, 0.3) grp:insert(tobj[#tobj]) if n == 100 then print("Delete group", cycle) local c = #tobj for i = 0, c do if not tobj[i] == nil then tobj[i]:removeSelf() tobj[i] = nil end end grp:removeSelf() grp = nil n = 0 tobj = nil cycle = cycle + 1 if cycle \> 10 then Runtime:removeEventListener("enterFrame", onEnterFrame) end end n = n + 1 end Runtime:addEventListener("enterFrame", onEnterFrame)

Doing a removeSelf() and nil’ing out the object is definitely the right thing to do.

Regarding keeping your memory size low, the key thing to remember is that the size of the PNG or JPEG files you are using doesn’t matter.  When you load an image via display.newImage(), display.newImageSheet(), etc… Corona must decode the image to a 32-bit color uncompressed bitmap in order to submit it as a texture to the GPU.  That’s 4 bytes per pixel, which also means the amount of memory a decoded image takes in memory is predictable.  Here’s the formula to make it a little more clear…

   totalMemoryInBytes = pixelWidth * pixelHeight * 4

Masks and text objects are loaded as 8-bit grayscale bitmaps.  So, they’re 1 byte per pixel, making them significantly cheaper than image objects.

Another useful tip is in regards to audio.  If you have any large audio files that you use for music, then you may want to use our audio.loadStream() API instead of audio.loadSound().  The audio.loadSound() function will decode the entire audio file to memory, which is really only suitable for short sound effects because you can play them quickly with little to no latency.  audio.loadStream() works kind of like Internet audio streaming, except it streams from file, loading small chunks (ie: audio frames) from file into memory and is intended for low-memory situations such as this.

Hi,

Thank you for your reply and tips. We’ve never optimized audio features so It’s worth for us to take a look into our sound functions.

Btw I found that the memory usage rises significantly when we use external font.

For example, when I added Osaka-mono font to the project of the first example of my latest post, and changed ‘native.systemfont’ to “OsakaMono.ttf#OsakaMono”, the heap size raised to 168MB after 100 cycles and could not be freed.

Is this behavior correct?

In our app, memory problem was almost solved when I switched the external font to system font. 

That’s interesting.  We’re actually loading fonts via Microsoft’s Silverlight because that’s our only native option on Windows Phone 8.0.  So, we’re at Silverlight’s mercy on when the font gets freed from memory, or, perhaps Silverlight keeps it cached for the lifetime of the app?  I really don’t know.  I’ve seen a similar question on Microsoft’s forum (link below) which might suggest Silverlight keeps the font cached.

   https://social.msdn.microsoft.com/Forums/silverlight/en-US/a53752fd-5aa3-4e2e-b9c4-1dc2ca3ce973/memory-leak-with-embedded-font?forum=silverlightnet

I remember testing embedded fonts several times before.  I don’t recall any memory leaks happening.  The issue you are seeing here is that its a big jump in memory usage when using embedded fonts, right?

Oh and one more thing.  You do have the option to use the system fonts that are installed on WP8 as well.  Microsoft documents the fonts available via the link below.  I’m thinking that since the default system font that is already installed and preloaded into memory isn’t taking much memory from your app (its memory usage might not be counted against your app’s memory usage), then the other system fonts won’t either.  Might be a nice option if you’re trying to distinguish different text using different fonts, although I suspect you’re using an embedded font so that your text object size is reasonably consistent between platforms.  In any case, it might be worth a go.

   https://msdn.microsoft.com/en-us/library/windows/apps/hh202920(v=vs.105).aspx

Thank you for your suggestion.

It seems that the more letters a font file contains, the more memory is consumed.

I did further test with other fonts that are installed in Windows 10: Vedana and YU Gothic.

I copied these files to project folder and loaded from corona as embedded fonts.

Here are the definitions.

– YU Gothic

local font = “YuGothic.ttf#Yu Gothic”

– Verdana

local font = “verdana.ttf#Verdana”

When I used YU Gothic, the memory usage raised to 299MB after 100 cycle show and remove test.

For Verdana, the result was 70 MB with the same test.

The difference of these fonts is as below:

YU Gothic … Contains both Japanese and Western letters, 4,721 KB

Verdana … Contains only Western letters, 235KB

In my conclusion, the apps in English will not be affected so much by the memory problem with font because they have only 26 letters,

but if you consider localize internationally with embedded international fonts, the app will be affected.

Our app shows text messages many times to tell the stories and affected by this problem well, so I’m now considering to use system font that you are recommending.

However, I also hope that you find any possibility to make the situation better in future, because the system fonts are not so cool :frowning: