Author Topic: Memory management problem  (Read 12102 times)

0 Members and 1 Guest are viewing this topic.

Offline Joel

Memory management problem
« on: March 24, 2002, 11:33:55 AM »
I was recently messing around in my game shapeshifting into all the different characters that it was possible to shapeshift into and suddenly my game crashed with an out of memory error. This isn't a serious problem, because it's unlikely to happen in practice (I was in debug mode, had changed some flags that prevented shapeshifting in certain situations), but I thought I might try to fix the problem. So, I added the following type code to the shapeshift command parsers.

Code: [Select]
if (said("shapeshift", "man"))
 {
   if (!bOnEarth)
   {
     // nCurrentEgoView is not v16

     if (nCurrentEgoView != FORM_GENERIC_MAN)
     {
       load.view(FORM_GENERIC_MAN);
       set.view(ego, FORM_GENERIC_MAN);

       if (bDiscardOldViewOnMorph)
       {
         discard.view.v(nCurrentEgoView);
       }

       nCurrentEgoView = FORM_GENERIC_MAN;
     }
     else
     {
       print (m1);
     }
   }
   else
   {
     print(m4);
   }
 }


The first time I do a morph, it works fine. If I then morph into a different form, the game gives me a view not loaded error message and quits. Obviously, the view seems to be loaded, because until two seconds ago it was assigned to ego (I checked the number of the view it said wasn't loaded and it was the correct view number for the view ego was just using).  Any ideas why this might be happening?
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »



Offline Nick Sonneveld

Re: Memory management problem
« Reply #1 on: March 24, 2002, 12:55:19 PM »
A couple of things go wrong here.. basically, agi expects you to discard resources in the same order they were loaded.. since ego's view is loaded right at the start of logic.0, it gets complicated.

the thing to remember is that agi allocates memory on a sort-of stack..  It also has linked lists containing all the loaded objects (separate ones for view, pic, sound, logic), with pointers to the memory heap.  

So the resource information is contained on the heap.. and the linked list contains information on it's whereabouts in the heap and which items are loaded.

so what you have before you shapeshift is probably:

mem = GAME->LOGIC.0->EGO_VIEW->LOGIC.ROOM->SOUND->VIEW->VIEW->NEXT
logic = LOGIC.0->LOGIC.ROOM
pic = 0  // always discarding pics hopefully
view = EGO_VIEW->VIEW->VIEW
sound = SOUND

The reason why ego view is at the start is because logic.0 always loads it for a new room.  The Next is the pointer to the next position in the memory heap.

so when you load up the new view, the memory will look like this:

mem = GAME->LOGIC.0->EGO_VIEW->LOGIC.ROOM->SOUND->VIEW->VIEW->*MAN_VIEW*->NEXT
logic = LOGIC.0->LOGIC.ROOM
pic = 0  // always discarding pics hopefully
view = EGO_VIEW->VIEW->VIEW->*MAN_VIEW*
sound = SOUND

and THEN you discard the ego view.. but this is where the algorithm of the agi memory gets screwy.. When agi removes an item from the view list, it just sets the next pointer of the *PREV* item to zero... since you're removing ego_view, the first item in the list, it will remove all the others too.

view = 0

that's not all.. to remove it from memory, it just sets the "next available space" pointer to point to EGO_VIEW, so when you load a new resource, it will overwrite the old resource.. this works fine.. but if you set the next available space to ego_view, new resources will write over ALL the other resources loaded in memory..

so the memory looks like this now:

mem = GAME->LOGIC.0->*NEXT*->EGO_VIEW->LOGIC.ROOM->SOUND->VIEW->VIEW->MAN_VIEW

So most of the items are still in memory, but when you load up another resource, it will load over them, AND the view list is destroyed, so the interpreter won't know about any of the loaded views..


That's why you get a "view not loaded" and possibly other weird stuff happening...

This is definately needed for a tutorial, it's kinda complicated, but I hope I made sense.  The main thing to remember is to discard in the same order you load.. even if it means having an ego view and a man view in memory at the same time.

- Nick
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »
Nick Sonneveld  |  AGI Dev  |  NAGI

Offline Joel

Re: Memory management problem
« Reply #2 on: March 24, 2002, 03:08:34 PM »
That actually does make sense. I think I remember hearing something like this before. It also explains why when I did a show mem the memory dropped from about 36000 bytes used to about 20000 bytes used.

I think I'm going to solve the problem by limiting the shapeshifting in all situations. I think it's better that then risking the game crashing by somebody morphing one too many times on the same screen.
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »

Offline Nick Sonneveld

Re: Memory management problem
« Reply #3 on: March 24, 2002, 03:59:52 PM »
I don't think it would be much of a problem.. just store a variable that contains the ego's view resource number for when it enters a room (it will be at the start of the mem heap) and make sure your shapeshift code doesn't discard it when swapping views.. just amy other ones that you load when shape shifting in that room.

You'll have, at max, two ego views loaded (the one you started with in that room, and the current).. but it's better than limiting yourself.

- Nick
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »
Nick Sonneveld  |  AGI Dev  |  NAGI

Offline Joel

Re: Memory management problem
« Reply #4 on: March 24, 2002, 04:51:50 PM »
ok. I did that but still ran into a problem with discarding the current ego view (it causes major problems to dispose of a view while it's associated with an object). So I created a 1x1 blank view resource and set ego's view to that, discarded the old view if it was safe, and then loaded and set the new view. It doesn't seem like it should work, but the game doesn't crash anymore and the show mem command reports the same amount of memory used every time I morph into the same form.
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »

Offline Nick Sonneveld

Re: Memory management problem
« Reply #5 on: March 24, 2002, 05:11:19 PM »
The reason why you shouldn't discard the view while it's still associated with an animated object is because there's other things going on with the memory manager I forgot to mention.

There's actually a list of animated objects, with blitting information.  But because it's dynamic, and it would have to be updated all the time, whenever something it added to the memory heap, the interpreter free's all the animated objects, allocates the new bit of memory and then allocates memory for the animated objects..  That way the animated objects are always at the end of the heap.

can't you keep another temp variable storing what the last view resource was?  then discard it after you're set it?

Another thing you could do, is in logic.0.. when it loads up the ego view resource.. you could add a check so it doesn't load it in the rooms where jen shapeshifts.. then in the room logic, you load up the ego as the last resource.. that way you can discard it at your leisure.

- Nick
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »
Nick Sonneveld  |  AGI Dev  |  NAGI

Offline Joel

Re: Memory management problem
« Reply #6 on: March 24, 2002, 05:12:33 PM »
I guess what is going on is this:

views->EGO_VIEW->VIEW->VIEW

when a shapeshift command is executed the first time

views->EGO_VIEW->VIEW->VIEW->NULL_VIEW->NEW_EGO_VIEW

and because the previous view is the view on room entry, no discard command is executed. On the second shapeshift command, it sets ego's view to NULL_VIEW (which is already loaded -- I guess the interpreter's smart enough not to load it twice), then it deletes NEW_EGO_VIEW and loads the next view in as NEW_EGO_VIEW. Unfortunately, this means I'll have to be very careful about loading new views in rooms where unrestrained shapeshifting is allowed., but I should be able to handle it.
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »

Offline Joel

Re: Memory management problem
« Reply #7 on: March 24, 2002, 05:15:49 PM »
I do keep a variable that says what the last view of ego was. But I think if I set ego's new view first and then discard the old, the same problem will happen where the resource linked list loses its reference to the newly loaded resource.
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »

Offline Nick Sonneveld

Re: Memory management problem
« Reply #8 on: March 24, 2002, 06:24:29 PM »
what I meant was not load the ego view until last..  

so in logic.0.. you stop it with an if statement.. after you've loaded all the other views, you load up the ego's view..
so the view list will look like:

view = VIEW->VIEW->EGO_VIEW

then you can safely discard the ego_view.. as long as you didn't load a sound or a picture after it.

- Nick
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »
Nick Sonneveld  |  AGI Dev  |  NAGI

Offline Joel

Re: Memory management problem
« Reply #9 on: March 24, 2002, 06:55:18 PM »
ok, I'm talking about something a little different. I mean when the view being discarded is not the initial ego view at the start of the room. I use what I've called the null view because I think if I don't then I'll get this situation

view = ORIGINAL_EGO_VIEW -> ... -> CURRENT_EGO_VIEW -> TARGET_EGO_VIEW

after I set ego's view to TARGET_EGO_VIEW, if I discard CURRENT_EGO_VIEW, won't that also discard (i.e., lose the memory reference to) TARGET_EGO_VIEW? It sets CURRENT_EGO_VIEW.prev.next to NULL?

I don't think keeping ORIGINAL_EGO_VIEW in memory eats up enough resources for it to be worth making serious modifications to the behavior already written into logic 0. In most situations where memory is tight, unrestrained morphing isn't allowed anyway. I'll keep that idea in mind in case I find out that it is a problem later on, but for now I think it's ok to just have two ego view resources in memory at once.
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »

Offline Nick Sonneveld

Re: Memory management problem
« Reply #10 on: March 24, 2002, 08:12:49 PM »
Sorry, I understand now.. you're trying to avoid having two views for the ego loaded.. even if you're just swapping them.

I think the best way would be the method you're using with the 1x 1 view..

my idea was to defer loading the ego view until later.. when you've loaded up the other resources.. that way you could safely discard it when swapping..

btw.. the interpeter's smart enough not to try and load resources twice, but it will still add an entry to the game script, despite the fact it's already loaded.  So eventually the script will fill up in that room.

- Nick
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »
Nick Sonneveld  |  AGI Dev  |  NAGI

Offline Joel

Re: Memory management problem
« Reply #11 on: March 24, 2002, 08:57:48 PM »
Ok. Two load.view commands get executed every time a morph command is executed. I know this depends on how much other stuff is loaded, but as a rough guess how many times would someone have to shapeshift in a single room to fill up the script buffer? Would it be a lot?

If so, I think I could probably leave checking for that kind of thing out, because there won't be that many reasons to morph in places where unrestrained morphing is actually allowed. If it's not a lot, I could put an upper limit on the number of morphs allowed in a single room or within a certain amount of time or something like that.
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »

Offline Nick Sonneveld

Re: Memory management problem
« Reply #12 on: March 25, 2002, 02:06:37 PM »
I can't remember what the default maximum is.. but you can set your own script size (right at the start!  before any menus, logics or anything else is loaded.. and only once).

mem.info also gives you the max script that was reached in the game.

There's a flag that disables writing to the script.. and two unknown functions save, restore the position in the script.

if you disable the script whilst morphing.. you'll have problems with saving/restoring though (because that's what the script's for!)..

so, before you save, .. disable script write, discard the ego view resource, enable script again and load the resource.

that way, when the restore game occurs, it will read the script.. load the last view resource, and then, when it assigns view resources to animated objects.. it will have a view loaded to associate with it.

i hope that made sense.

- Nick
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »
Nick Sonneveld  |  AGI Dev  |  NAGI

Offline Joel

Re: Memory management problem
« Reply #13 on: March 25, 2002, 02:52:11 PM »
The default size is 50, and it takes probably somewhere between 15 and 25 morphs to overflow the buffer.

Ok, I'm not 100% clear what you're saying. Let me say it back to you to see if I understand. What you're saying is that I should write something like this:

Code: [Select]

 if (said("shapeshift", "man"))
 {
   if (!bOnEarth)
   {
     if (nCurrentEgoView != FORM_GENERIC_MAN)
     {
       // disable script buffer
       set(script_buffer_blocked);

       load.view(FORM_NULL);
       set.view(ego, FORM_NULL);

       if (bDiscardOldViewOnMorph &&
           nCurrentEgoView != nEgoViewOnRoomEntry)
       {
         discard.view.v(nCurrentEgoView);
       }

       load.view(FORM_GENERIC_MAN);
       set.view(ego, FORM_GENERIC_MAN);

       nCurrentEgoView = FORM_GENERIC_MAN;

       // reenable script buffer
       reset(script_buffer_blocked);
     }
     else
     {
       print (m1);
     }
   }
   else
   {
     print(m4);
   }
 }


then when a game is saved I should say something like
Code: [Select]

if (bDiscardOldViewOnMorph &&
   nCurrentEgoView != nEgoViewOnRoomEntry)
{
   set(script_buffer_blocked);
   load.view(FORM_NULL);
   set.view(ego, FORM_NULL);

   discard.view.v(nCurrentEgoView);

   reset(script_buffer_blocked);

   load.view.v(nCurrentEgoView);
   set.view.v(ego, nCurrentEgoView);
}

// now save the game here



is that what you're saying?
« Last Edit: December 31, 1969, 07:00:00 PM by 1018072800 »

Offline Nick Sonneveld

Re: Memory management problem
« Reply #14 on: March 25, 2002, 04:06:23 PM »
I haven't tested it myself.. but that's the idea.

I'd actually be interested if it does work.. because it was just a theory I had in my head and if it works, it would help lots of people who want to continuously load random resources in a single room.

ie, a jukebox that plays different music but there's not enough room to load all sounds at once.

- Nick
Nick Sonneveld  |  AGI Dev  |  NAGI


SMF 2.0.19 | SMF © 2021, Simple Machines
Simple Audio Video Embedder

Page created in 0.17 seconds with 21 queries.