17 June 2013
When you’re developing interactive content, the primary goal is to deliver a great user experience. Whether you’re developing a game, a mobile app, or an interactive website, you want it to be fast, responsive, and accessible. Achieving this objective isn’t just about making your code run fast. You also have to consider the memory requirements of your content. Mobile devices have limited memory available to them, so if you’re not careful, you could significantly limit your audience. Not only that, but allocating and deallocating memory is slow, so it’s best to avoid unnecessary memory allocations.
Adobe Scout is an essential tool for debugging memory problems in Flash content, whether it’s running in the browser with Flash Player, or packaged as a mobile app with Adobe AIR. In this article, you’ll learn how to use Scout to identify memory problems, and determine what’s causing them. In particular, you’ll learn how Flash Player manages its memory usage, and how to understand the memory data you see in Scout. You’ll also learn how to use the new memory allocation tracking feature introduced in Scout 1.1, which lets you quickly identify specific objects that are resident in memory, and where they were allocated.
Note that this article only covers the features of Scout related to memory profiling. If you haven’t used Scout before, or you’re interested in performance or graphics profiling, you should start by reading the getting started guide.
Before you start using Scout to debug memory problems, it’s useful to have an understanding of how Flash Player manages memory. Internally, there are two pools of memory from which Flash Player can allocate: managed memory and unmanaged memory.
Managed memory is controlled by a garbage collector, and doesn’t require explicit deallocations. All ActionScript objects are stored in managed memory, as well as some objects that are used internally by Flash Player. Essentially, Flash Player allocates a big chunk of memory from the operating system, and uses this to store new objects. When it starts to run out of space, Flash Player tries to avoid asking the operating system for more memory, by running a garbage collector to see if it can recover any of its existing memory. The garbage collector walks through the managed memory and determines which objects are dead, then reclaims the memory that they’re using (a process known as "mark and sweep"). A dead object is one that can’t be accessed from ActionScript, because there’s no way to reference it. If the garbage collector can’t recover enough memory, it asks the operating system for more, and expands the managed memory pool.
Unmanaged memory is directly controlled by Flash Player, and requires objects to be explicitly deallocated when they’re not needed any more. You can’t allocate unmanaged memory directly from ActionScript, but certain large data structures are stored in unmanaged memory behind the scenes, including images, SWF files, and ByteArrays. If you create an ActionScript object that references this data, such as a display object created from an image, it acts as a handle for the underlying unmanaged memory. Any unmanaged memory that’s referenced by an ActionScript object will get deallocated when the object is garbage collected (assuming it’s the only object that references it).
Figure 1 shows how Flash Player interacts with these memory pools. The grey objects are technically dead because there’s no way to reference them, but they won’t get deallocated (along with the referenced Bitmap) until the next time the garbage collector runs. To learn more about how the garbage collector works, read Garbage collection internals for Flash Player and Adobe AIR.
Before you start a new session in Scout, you can select what data to collect under Settings for New Sessions. Regardless of what you select, every session records some basic data about what’s going on inside Flash Player, including high-level data about how much memory your content is using. You can see this in the Memory section of the Frame Timeline and Summary panels (see Figure 2).
The graph in the Frame Timeline shows how much memory Flash Player was using at the end of each frame, broken down into categories. This is just a periodic snapshot of memory usage, but it’s really useful for spotting memory leaks, which cause memory usage to steadily increase over time, and not decrease again even when the garbage collector runs.
The Summary panel shows you the memory usage over the selected range of frames. By default, it shows you the current memory usage–a breakdown of the memory in use at the end of the last frame in the selection. If you click the gear button you can change the display to either the average or the peak memory usage over the selected frames (see Figure 3). The precise meaning of these settings is as follows:
If you look closely at the data in the Summary panel, you'll notice that Scout distinguishes between total memory and used memory. To speed up allocations, Flash Player doesn't ask the operating system for more memory every time it needs to allocate an object. Instead, it obtains large blocks of memory from the operating system, and performs internal allocations within these blocks. This is true of both managed and unmanaged memory. The total memory is the sum of all the blocks obtained from the operating system, and the used memory is the amount of memory from these blocks that Flash Player is actually using.
The total memory that Scout reports will usually be a bit lower than what you see in the OS X activity monitor or the Windows task manager. This is because there are some resources that get allocated directly by the operating system, rather than by Flash Player itself, such as file handles and graphics resources. This additional memory usage is small, and it's usually nothing to worry about.
To help you identify memory problems, the summary panel breaks down used memory into five top-level categories:
The Bitmap category is broken down into a number of subcategories. You might not see all of them when you run your content, because Scout hides categories that aren't applicable. The subcategories of Bitmap are as follows:
The Other category contains memory used for miscellaneous purposes that don't fall neatly into one of the other categories. It also has a number of subcategories:
Note that ActionScript Objects is the only category that uses managed memory. If your content continually allocates and then discards a lot of objects, this category tends to follow a sawtooth pattern (see Figure 4). As Flash Player allocates new ActionScript objects on every frame, the memory usage gradually creeps up. After a while, there isn't any space left to allocate more objects, and this triggers a garbage collection. At this point, Flash Player recovers the memory of the objects that are no longer referenced, and the memory usage drops sharply. Notice that the total memory doesn't decrease; Flash Player keeps the memory it's already obtained from the operating system, because it's probably going to fill it again!
The problem with this behavior is that garbage collection is a computationally expensive operation, and it can cause your content to stutter when it happens. If you have a high turnover for a certain type of object, it’s a good idea to use object pooling so you can reuse the same objects without having to allocate new ones. Of course, you first need to figure out which objects are causing the problem. Thankfully, Scout 1.1 includes a new Memory Allocation Tracking feature that lets you do just that!
To get a detailed breakdown of which objects are in memory, turn on Memory Allocation Tracking, under Settings for New Sessions (see Figure 5). This will cause Flash Player to record memory allocations and deallocations, and send this data to Scout. Flash Player tracks every allocation that your ActionScript code makes, along with the big allocations that it makes on your behalf (specifically, items that fall under the Bitmap, ByteArrays, and SWF Files categories). Note that it doesn’t record every single allocation that Flash Player makes; only the ones that are a direct consequence of running your content.
The Memory Allocation Tracking setting requires a debugger version of Flash Player if you’re running your content in a web browser. You don’t need to do anything special for AIR content; you can use this setting to profile your release content. Also, remember that your content must have Advanced Telemetry enabled to use this feature. To learn how to enable this, read the getting started guide.
You can view the data that Flash Player gathers in the Memory Allocations panel in Scout. The default view of this panel shows the ActionScript stack traces where objects were allocated, within the frames you selected (see Figure 6). If you expand the stack traces, you can see how many objects of each class it allocated. You can also see allocations that happened outside of ActionScript due to internal Flash Player activities. For example, Figure 6 shows that "Preparing ActionScript Bytecode" caused 20 allocations.
By default, the Memory Allocations panel only shows you the allocations of objects that were still live at the end of the last frame in the selection. In other words, it doesn’t show you objects that were allocated, but got garbage collected during the frames you selected. If you want to see all objects, including those that were already garbage collected, you can turn off the Hide Garbage-Collected Objects filter (see Figure 7).
It’s important to note that the Memory Allocations panel shows you only the objects that were allocated during the frames you selected. It doesn’t include objects that were allocated on an earlier frame, even if they’re still live in the selected frames. If you want to see all the live objects in frame n, you need to select frames 1 through n in Scout.
While the top-down view is useful for understanding where allocations happened in relation to the execution of your code, you often just want to know the total number of allocations for each type of object. The Bottom-Up Objects view displays the number of allocations of each class (see Figure 8). You can expand an object to find out what caused the allocation.
You might be wondering why the objects are not colored the same as the function calls. It’s because the objects are colored according to what memory category they belong to in the Summary panel. While most allocations are ActionScript objects, Scout also shows you other big allocations. For example, the allocations taking up the most memory in Figure 9 are due to Bitmap DisplayObjects. You can see that these were created internally by Flash Player when a texture was uploaded, and when it was decompressing images.
As well as seeing which classes were allocated the most, it’s also useful to see which functions performed the most allocations. This can help you to optimize specific functions. For example, you could reuse objects rather than allocating new ones every time. The Bottom-Up Functions view lists each function according to how many allocations it made directly, as opposed to indirectly by calling another function (see Figure 10).
You can expand a function to see both a breakdown of the objects that were allocated across all invocations of the function, and which other functions were responsible for invoking it.
So far, you’ve seen how you can use the Memory Allocations panel to look at allocations, but it also lets you see when objects are deallocated. If you change the Allocations setting to Deallocations, you can see all the objects that were deallocated during the selected frames. You can also filter the Memory Allocations panel from the Activity Sequence or Top Activities panels (see Figure 11). This works just the same way as filtering the ActionScript panel, and it lets you see what objects were deallocated in a specific garbage collection.
While profiling a live session, you can force Flash Player to stop what it’s doing and perform a full garbage collection by clicking the button in the top-left corner of the Memory Allocations panel (see Figure 12). This is really useful for ensuring that the objects you’re looking at in Scout are really live, and not just waiting to get garbage collected.
There are a few things to watch out for when using Scout for memory profiling:
Now that you know more about the memory model of Flash Player and the memory profiling features of Scout, you’ll be more effective at identifying and tracking down memory problems in your own content. To find out more about how Flash Player works, you can read the articles Garbage collection internals for Flash Player and Adobe AIR and Understanding Flash Player with Adobe Scout.
Comments are currently closed as we migrate to a new commenting system. In the interim, please provide any feedback using our feedback form. Thank you for your patience.