03 Nov, 2009, Scandum wrote in the 21st comment:
Votes: 0
quixadhal said:
Soooo, changing the "string_space" variable to an array is one option. When you fill up the first block, you'd calloc() off another one as string_space[1] and all new strings would be allocated from there….

I think that would require additional checks for each index used to see if a pointer points to string space? It's possible to write a dynamic shared string manager using a hash table, it's not overly complicated.
04 Nov, 2009, Mudder wrote in the 22nd comment:
Votes: 0
After seeing this thread I booted up RaM fire checked the memory command. Did random things and checked it again and compared them.

I noticed that every single time I log a character in, RaM allocated more perm blocks. So I decided to mess around with it. I made two lowbies and logged them both in, checked the memory.

Affects 743
Areas 48
ExDes 1115
Exits 7295
Helps 271
Socials 244
Mobs 986(986 new format)
(in use) 2731
Objs 1264(1264 new format)
Resets 4573
Rooms 3126
Shops 62
Strings 17044 strings of 1327174 bytes (max 1413120).
Perms 28988 blocks of 2458108 bytes.

Then I logged them in again, also checking the memory.

Affects 743
Areas 48
ExDes 1115
Exits 7295
Helps 271
Socials 244
Mobs 986(986 new format)
(in use) 2731
Objs 1264(1264 new format)
Resets 4573
Rooms 3126
Shops 62
Strings 17044 strings of 1327174 bytes (max 1413120).
Perms 28991 blocks of 2458156 byte

Shouldn't it be recycling these instead of allocating more?
04 Nov, 2009, Mudder wrote in the 23rd comment:
Votes: 0
So with more experimenting I found that it only happened when they were in a clan.
04 Nov, 2009, David Haley wrote in the 24th comment:
Votes: 0
If this is a RaM-Fire specific problem, it should probably be in a different thread (e.g., in the RaM forum).
04 Nov, 2009, Mudder wrote in the 25th comment:
Votes: 0
I actually assumed it was a ROM problem.

After some testing I confirmed that ROM also has this issue and another one I haven't narrowed down. It allocates one without a clan, and with a clan it increases to two.
04 Nov, 2009, Tyche wrote in the 26th comment:
Votes: 0
Mudder said:
Shouldn't it be recycling these instead of allocating more?


I would expect the counts to go up for a while after a new boot, because there are a number of different kinds and differently sized objects allocated with alloc_perm. Perhaps if you logged in and logged off a score of characters and continued to see it rise, then I'd think to look for a leak.
04 Nov, 2009, Mudder wrote in the 27th comment:
Votes: 0
So I went through some known bug lists for ROM. I found the solution and it seems to have worked just fine. This is the exact copy from the bug file.

Ok, I've found some more stock ROM memory leaks…  damn.

These are all in save.c.

In fread_char():

KEY( "Clan", ch->clan, clan_lookup(fread_string(fp)));

The problem with this is, fread_string() is going to str_dup() whatever
it reads in… and this never gets freed. To fix this, you have to
keep a pointer to the string you read in:

if ( !str_cmp( word, "Clan" ) )
{
char *tmp = fread_string(fp);
ch->clan = clan_lookup(tmp);
free_string(tmp);
fMatch = TRUE;
break;
}

In that same function, the same thing is done for race:

KEY( "Race", ch->race, race_lookup(fread_string(fp)));

This needs to be fixed in the same way.

And also, fread_pet() contains duplicates of these errors reading race
and clan values.

Can't believe I missed that one for all this time, bleah.


I believe I got the bug list from mudbytes, but it's been so long I don't actually know anymore. :)
04 Nov, 2009, elanthis wrote in the 28th comment:
Votes: 0
Quote
Unless I missed it somewhere, ROM never actually frees memory, it allocated it and then puts "unused" chunks onto a free list to be recycled. Historically, that's because malloc() and the underlying sbrk() it uses were very expensive operations


free() doesn't usually release memory, either. The standard library memory allocator does the same thing the ROM allocator does, it just does it better. sbrk() can only resize the heap, which means that it can only release memory if all the memory you want to release is at the end of the memory space requested by sbrk(). Modern versions of malloc() will often use mmap() to allocate larger chunks of memory instead of using the heap space allocated by sbrk(), which is the only reason that free() might release any memory at all back to the OS in most cases.

It's still very common to use custom memory allocators in high performance scenarios, from games to script language interpreters. System memory allocators are optimized for general cases instead of specific cases, so things like string allocations are lumped in with everything else instead of being given a allocator better designed for the common allocation and deallocation patterns of strings. Strings in many interpreted languages especially are often allocated and quickly deallocated as small temporary chunks, for example. Even if you're not using a generational GC for most objects, using them for strings is a fantastic idea in many VMs.

ROM's setup is still stupid, though. ;)
04 Nov, 2009, quixadhal wrote in the 29th comment:
Votes: 0
Yep, and that's one of the bugs we looked at and said, nevermind. Because our intent was to replace all those strings with std::string objects, any bugs related to not freeing string memory were considered redundant effort. In other words, when fread_string doesn't use str_dup anymore, the problem goes away.

Probably worth fixing in RaM Ice though, if I (or anyone else) ever gets around to it. :)
05 Nov, 2009, Davion wrote in the 30th comment:
Votes: 0
Tyche said:
This article might be helpful, RomMemorySystem


Also, this might help!… But seriously! I actually took a few minutes to sit down and look at this magical string handler and all I can say is… wow! :P. First off, 90% of the sharing of strings -only- happens when fread_string is called. The only time, during the life of the game when a string is shared, is when it's assigned to a string already within the bounds of the string chunk (string_space to top_string). Any other string (not within those bounds) is simply allocated.

It's rather unfortunate you can't simply call a realloc() at the top of fread_string when string_space gets over flowed, but that'd void all the pointers currently pointing to sections in the shared space. Unless you started tracking pointers to the strings (essentially writing your own shared string code) to reset once a realloc is called, you might just be stuck increasing when the need comes, or stepping away from it entirely.
05 Nov, 2009, Scandum wrote in the 31st comment:
Votes: 0
Simply duplicate string pointers when creating an object/mob/room from the index data. Requires editing the object/mob/room creation/deletion code, problem solved. The whole string space thing is silly.
20.0/31