GameMonkey Script

GameMonkey Script Forums
It is currently Tue Mar 19, 2019 6:52 pm

All times are UTC




Post new topic Reply to topic  [ 13 posts ] 
Author Message
PostPosted: Fri Oct 24, 2008 1:49 pm 
Offline

Joined: Wed Sep 03, 2008 10:39 pm
Posts: 15
Each of my GM scripts is basically a bunch of global functions and variables. The scripts are loaded and unloaded as required.

I've put a callback into gmThread::Sys_Execute so that I can record when a global is set (BC_SETGLOBAL). Then when I load my script I call gmLibHooks::BindLib and record all the globals that are set as part of that script.

When I want to unload the script I simply set each of the globals for that script to gmVariable::s_null and hope that they get GC'd. Although the GC does seem to be working I am also using way more memory in GM than I should be. So my question is, is this approach the correct way to go about loading and unloading scripts on demand? How can I be sure that all my globals are being GC'd when they are no longer needed?

thanks,
Chris


Top
 Profile  
Reply with quote  
PostPosted: Fri Oct 24, 2008 3:21 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
You would need to do a full collect after an unload to collect all the released globals. machine->CollectGarbage(true)


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 24, 2008 12:32 pm 
Offline

Joined: Wed Sep 03, 2008 10:39 pm
Posts: 15
Sorry for the late reply! We are doing a full garbage collection periodically, and we do seem to get some memory back. We have concerns though that GM is still being a bit greedy with its allocations. Is there a way to just completely disable the garbage collection and do all allocation and frees immediately? This would allow us to see how much of our GM memory usage is down to GC slack and greediness.

Would it be as simple as changing Sys_Alloc and Sys_Free to call our own memory routines?

thanks,
Chris


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 25, 2008 9:02 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 708
GM can be a bit greedy, but with a calibrated GC, should not consume too much excess memory.
You can force a GC full collect as often as you like, such as after every script call, or every game/app frame if needed.
You could enable the GMMACHINE_GCEVERYALLOC #define which will can cause the GC to run constantly. If you do this, make sure the bindings and usage of GM are valid. That is to say, because that option is not enabled by default, coders can get away with not disabling the GC around accesses to unconnected new objects or such and not realize the consequence.


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 27, 2008 8:49 pm 
Offline

Joined: Tue Dec 04, 2007 8:00 pm
Posts: 26
This is going to sound crazy but one thing I noticed is that windows doesn't seem to actually free the memory from the game's memory space until you click the minimize button on the window (!). Often times, task manager will say my game is using 100+ megs of memory, but then when I click the minimize button on the window, the usage amount goes down to as little as 8 megs and then works itself self back up again as more allocations occur. If the game is paused then usually it'll go up a little bit and then hover, probably because the update code isn't executing and thus not generating a whole lot of allocations.

That sounds insane, and perhaps it's just my code or some third party platform-specific code that's causing this, but maybe, just maybe this is what's happening to you too?

-j


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 28, 2008 11:55 pm 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 708
That memory behavior does sound unusual. I have often used Windows Task Manager to watch a real time program use and release memory. I presume your game has a standard windows message pump or yields to the OS regularly?


Top
 Profile  
Reply with quote  
PostPosted: Sat Nov 29, 2008 5:32 pm 
Offline

Joined: Wed Sep 03, 2008 10:39 pm
Posts: 15
We are running our code on an NDS, so that shouldn't be a problem for us. :)


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 30, 2008 3:20 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 708
treething wrote:
We are running our code on an NDS, so that shouldn't be a problem for us. :)

One thing to try is run some similar code using GME.exe on Windows and see how its memory usage compares. You can use the sysGetMemoryUsage() and similar functions to monitor memory usage or look at the snake.gm example script. The point here is to determine if GM is behaving as expected.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 29, 2009 10:10 am 
Offline

Joined: Fri Jun 19, 2009 12:39 pm
Posts: 31
I'm currently trying to figure out a way to unload whole script libraries that I've added with ExecuteLib(). Is there an easy way to to this, or is this something that I need to write some support code for?

I have two classes of script code at the moment; transient and persistent scripts. Transient scripts are to be unloaded, and possibly re-loaded at certain times (like when a level closes, and a new level loads) with the persistent scripts staying for the entire life time of the app.

I could just destroy the VM, load the persistent code again along with re-registering any custom types. The problem is that my persistent script code may need to preserve state, and of course, this state is lost due to the reset.

So...what's the easiest method for unloading a library?


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 29, 2009 11:27 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 708
BinaryDad wrote:
... So...what's the easiest method for unloading a library?

Could you group the library functions and members under one table eg. 'g_level', then null it at level exit time?


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 29, 2009 1:03 pm 
Offline

Joined: Fri Jun 19, 2009 12:39 pm
Posts: 31
Greg wrote:
BinaryDad wrote:
... So...what's the easiest method for unloading a library?

Could you group the library functions and members under one table eg. 'g_level', then null it at level exit time?


Hmm....I could do this. Would this work across multiple script files/libraries?

So in say, Car.gm I have

Code:

global g_transientScript = table
{

   CarSetup = table
   {
        blah blah blah
   },

   CarCreate = function(credit, name)
   {

   }
};


And then in say, Level1.gm I have

Code:

global g_transientScript = table
{
    LevelStart = function()
    {

    },

    LevelEnd = function()
    {
 
    }
}



So basically, I'm declaring the table in two separate files; will this then resolve to a single table, or will this cause issues by recreating the table the second time around?


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 29, 2009 1:33 pm 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 708
The line...
global g_transientScript = table
...is a killer. It will overwrite any existing global table. You have a range of syntax options to avoid this though. Member syntax is probably the simplest. It's all dynamic, so adding, taking and changing members is a normal thing to do.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 29, 2009 2:13 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
In my project I have a global "Map" table which is the container to hold data loaded by the map/level script. It is nulled on level change(actually just re-assigned to a new Map table, the old shit will be GC'd). Point being that the only way to do what you want is to hold data on a user object or in a table that you can then remove the reference to from the global table, which will allow the GC to clean it up.

I have added 'module' support to the GM I maintain. It works similar to lua modules. It's basically implemented using a table. For example

Code:
global Util = import("utilities");


This code basically just loads utilities.gm into a table, adds a reference to it in a global _MODULES table, and returns the reference as well. This allows any number of scripts to import it and it will only be loaded once. I don't have a function to unload a module, because even if I did a _MODULES["utilities"] = null;, any reference being held by other scripts would keep the module alive, so you can't truely 'unload' the module. What is possible though is redefining. I don't do this currently because I have no need, but it should be possible, on level load, or whatever, to effectively re-import a module and replace its contents, so long as you do so in the same table previously allocated. For example, a function like this:

Code:
clearmodule("utilities");


might effectively do a _MODULES["utilities"] = null; AND clear the table, so it's completely empty, which means the next time someone calls the first line of code to import utilities, it can re-populate the utilities module table with new shit, and not break any of the existing held references to the module.

My map function is not protected to this extent, as I don't expect people to be storing references to the map table. If they did it would cause problems. Kinda think it would be useful if there were some way to prevent references from certain objects from being assigned to a variable.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group