Making snapshots of the current state
At any moment while the tool is
connected to your game, you can press a button to make a snapshot of
the current memory state. This snapshot is stored in a list (see
again figure 1). A snapshot can be analysed in exactly the same ways
as the current state can be analysed.
Snapshots are particularly useful to
find memory leaks. The CallGraph and TopX views that were discussed
earlier can also be used to compare different states with each other.
The views support dual-screen: the left screen displays the state
from snapshot A and the right screen displays the state from snapshot
B.
How does this help to track memory leaks? Well, the views can be
ordered to view only the differences between those states (see again
figure 2). If snapshots are created at moments in the game where the
memory layout is expected to be equal, you can compare snapshots and
see if snapshot B contains memory allocations that snapshot A does
not have. If your game has a main menu, this may be a good point to
compare snapshots in. The previous article discussed the algorithm
for this comparison methodology.
Snapshots can also be controlled
programmatically by the game. The game can order the tool to create a
snapshot by using the MemAnalyze API. Some snapshots are more
convenient to control from within the game. For instance, it may be
helpful to create a snapshot right before the game is exited.
Recording
the memory state
By recording the memory state we can
see how the memory behaves over time (see figure 6). Because it is an
actual recording we can also go back in time. We can put the cursor
on any location in the history and perform the same four types of
analysis as we could perform with the snapshots and the current
state. While this is quite powerful already, we can also compare
states within the recording in the same way we used to compare
snapshots. You are probably not going to search for memory leaks in
this view, but you can get some very interesting information out of
this view. We use it for the following two types of analysis:
-
Logical memory leaks. Let
me try to explain what I call logical leaks. Imagine your
game has an enemy and that enemy is not deleted during the game, but
it is deleted properly at the end of your game because all enemies
are, for instance, located in a global game object list that will be
destroyed at the end of the game. Traditional memory managers cannot
track these kinds of leaks easily as they will not report the
objects as being still allocated after the game is finished.
However, if you are playing the game for long enough, the memory
usage grows and grows until you run out of it. These problems are
hard to tackle - I am speaking from experience. This view will
simply show you that the memory size is growing and you can see the
culprit right away by, for instance, comparing two states from the
recording in the CallGraph view.
Figure 6: The recording view. This
part was recorded while launching the game. At some point the figure
shows hectic allocation behaviour, which turned out to be the loading
of very large lightmaps. This is a good candidate for optimisation.
We can also send Markers to the
tool by using the MemAnalyze API in a similar way as snapshots can be
sent to the tool. Markers differ from snapshots by the fact that they
do not store the current state – instead they are simply points in
time that are being inserted into the recording view. When recording
you can easily browse through the markers in your recording view. A
use for markers can be to send a marker to the tool each frame. You
can then see how memory behaves within markers – in this case, a
single frame.
|