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); } } }
Thanks.