Memory, GC, World of Warcraft and You Part II

#0 - Sept. 7, 2007, 7:20 p.m.
Blizzard Post
In the first installment of this series (http://forums.worldofwarcraft.com/thread.html?topicId=75469222), I presented an introduction to the incremental garbage collection system that was changed in the 2.0 codebase for World of Warcraft. Since this time there have been further observations, more testing, and better information with regards to the garbage collection system, so I wanted to provide an update.

How Does GC Work in World of Warcraft?

In Lua 5.0 (which was used in WoW prior to The Burning Crusade, the client used an atomic garbage collection system. What this meant was the system did nothing until you reached 200% of your starting memory usage, and then went through all objects in the system and collected those that weren't referenced anywhere.

In Lua 5.1, which is used in The Burning Crusade and beyond, an incremental garbage collection system was introduced. This garbage collection system has two steps:

* March through each object in the system and mark those that cannot be collected
* Collect any objects that have not been marked

In WoW, everytime a new object is allocated (strings, functions, tables, coroutines) the system takes a small slice of time, and runs through part of the garbage collection process. If the system is in the marking phase, then it will mark a few objects and then return to the rest of the system. When the mark phase is done, the system will deallocate a small slice of objects, each time new memory is allocated.

You can see how this works by doing the following:

1. Run the following script:

/script collectgarbage("collect"); collectgarbage("restart"); ChatFrame1:AddMessage(tostring(gcinfo())); for i=1,1e5 do local t = {} end; ChatFrame1:AddMessage(tostring(gcinfo()))

You should have two numbers printed to your chatframe, the first being your memory before creating a bunch of garbage and the second being your usage after creating the garbage. You should see a difference of around 2000 between these two numbers.

2. Run the same script, change "restart" in the second collectgarbage() call to "stop". You should see a difference of around 4000 between the two numbers.

3. Run /script collectgarbage("restart")

In the first example, the incremental garbage collector is running, so some of the new tables that are created are automatically deallocated by the system. In the second example, the garbage collector is off, so you can see that twice the memory is used by the system (since nothing is deallocated).

So is there a problem?
For most systems no. Any memory that is allocated will eventually be deallocated, but the overall system memory usage may appear to be a bit higher, since the garbage collector is a slower incremental process. If you have an extremely low amount of memory in your system, you could see some slowdown but it wouldn't be typical. There is one issue that can occur

What issue?

Consider the following description of the default garbage collection system:

* Memory is only deallocated when new memory is allocated.
* If the system has a large burst of garbage created by an addon, that garbage exists in the system
* Afterwards, in order for that to be collected, new allocations need to happen
* The default resting UI doesn't have a very large increasing rate of memory usage

As a result, it's very easy for a lot of garbage to be created that won't be collected for quite some period of time (with the default ui, as many tables as we created take longer than 5 minutes to collect). This doesn't cause an issue, but does show inflated numbers. The default garbage collector is doing exactly what it should do, but it can cause an addon to show a much higher memory usage number than intended.

How do we fix this non-problem?

Download the following addon that I have created: http://www.wowinterface.com/downloads/info7522-GCTweak.html

This addon is designed to run the garbage collection system periodically (over time) in addition to the way it responds to new memory allocations. These steps are only run when the player is not in combat, and only when their framerate is higher than the setting for the addon.

Once you're in game, run /gct <num> where <num> is a framerate you'd like the addon to be active when you're running faster than that. The addon should not negatively effect your framerate or system performance, but you can always turn the addon off if you find something different.

Net effect, you will have lower memory usage, and the garbage collector will be operating a bit closer to how it was intended. Feel free to ask any questions you have about the garbage collection system, (including very technical ones). This post is intentionally not very technical, and I know it can be very confusing :P

TLDR - Technical Version

Lua's incremental garbage collector only marks and deallocates in response to new allocatio
#4 - Sept. 8, 2007, 12:06 a.m.
Blizzard Post
FYI, something along these lines is in for 2.3.