I was reminded about the flash.sampler API by Grant Skinner’s recent post about it. While only available in the debug player, it can still tell us some valuable information about what goes on in the release player. Today I’m using the getSize function to find out how much memory overhead various classes impose, even when they are empty.

getSize is a simple function. All you do is pass in an object and it will return the size of it in bytes. So I tried making a lot of “empty” objects (eg. Array, Dictionary) and threw in a couple of basics (eg. int, Number) just for good measure. The test was extremely straightforward:

package
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.sampler.*;
	import flash.system.*;
	import flash.text.*;
	import flash.xml.*;
	import flash.utils.*;
 
	public class SizeOfEmpty extends Sprite
	{
		public function SizeOfEmpty()
		{
			var logger:TextField = new TextField();
			logger.autoSize = TextFieldAutoSize.LEFT;
			logger.defaultTextFormat = new TextFormat("_typewriter", 8);
			addChild(logger);
 
			if (!Capabilities.isDebugger)
			{
				logger.text = "Debug player is required to run this tool";
			}
			else
			{
				logger.text = "Object: " + getSize(new Object()) + "\n"
					+ "Array: " + getSize(new Array()) + "\n"
					+ "Vector.<int>: " + getSize(new Vector.<int>()) + "\n"
					+ "Vector.<uint>: " + getSize(new Vector.<uint>()) + "\n"
					+ "Vector.<Number>: " + getSize(new Vector.<Number>()) + "\n"
					+ "Vector.<Object>: " + getSize(new Vector.<Object>()) + "\n"
					+ "ByteArray: " + getSize(new ByteArray()) + "\n"
					+ "Dictionary: " + getSize(new Dictionary()) + "\n"
					+ "String: " + getSize(new String("")) + "\n"
					+ "Class Instance: " + getSize(new EmptyClass()) + "\n"
					+ "Dynamic Function: " + getSize(function():void{}) + "\n"
					+ "Instance Method: " + getSize(instanceMethod) + "\n"
					+ "Static Method: " + getSize(staticMethod) + "\n"
					+ "BitmapData: " + getSize(new BitmapData(1, 1, true)) + "\n"
					+ "EventDispatcher: " + getSize(new EventDispatcher()) + "\n"
					+ "Sprite: " + getSize(new Sprite()) + "\n"
					+ "MovieClip: " + getSize(new MovieClip()) + "\n"
					+ "TextField: " + getSize(new TextField()) + "\n"
					+ "Shape: " + getSize(new Shape()) + "\n"
					+ "Loader: " + getSize(new Loader()) + "\n"
					+ "Error: " + getSize(new Error()) + "\n"
					+ "Event: " + getSize(new Event("")) + "\n"
					+ "XML: " + getSize(new XML()) + "\n"
					+ "XMLNode: " + getSize(new XMLNode(1, "")) + "\n"
					+ "RegExp: " + getSize(new RegExp()) + "\n"
					+ "Matrix: " + getSize(new Matrix()) + "\n"
					+ "Matrix3D: " + getSize(new Matrix3D()) + "\n"
					+ "Vector3D: " + getSize(new Vector3D()) + "\n"
					+ "Point: " + getSize(new Point()) + "\n"
					+ "Rectangle: " + getSize(new Rectangle()) + "\n"
					+ "Timer: " + getSize(new Timer(1)) + "\n"
					+ "Namespace: " + getSize(new Namespace()) + "\n"
					+ "Boolean: " + getSize(new Boolean(true)) + "\n"
					+ "int: " + getSize(new int(44)) + "\n"
					+ "uint: " + getSize(new uint(44)) + "\n"
					+ "Number: " + getSize(new Number(44.0)) + "\n";
			}
		}
		private function instanceMethod(): void {}
		private static function staticMethod(): void {}
	}
}
class EmptyClass {}

I then ran it in the latest debug player in Firefox on Windows XP and got these results:

Type Size (in bytes)
Object 24
Array 40
Vector.<int> 48
Vector.<uint> 48
Vector.<Number> 48
Vector.<Object> 56
ByteArray 80
Dictionary 32
String 28
Class Instance 8
Dynamic Function 666
Instance Method 32
Static Method 32
BitmapData 68 (includes 4 bytes for the single pixel)
EventDispatcher 56
Sprite 420
MovieClip 452
TextField 1096
Shape 248
Loader 320
Error 44
Event 32
XML 16
XMLNode 48
RegExp 48
Matrix 56
Matrix3D 80
Vector3D 40
Point 24
Rectangle 40
Timer 88
Namespace 8
Boolean 4
int 4
uint 4
Number 4

And here they are in graph form:

There are some interesting finds here:

  • Number (an 8-byte floating-point value), Boolean (a single bit of data), int (a 4-byte signed integer), and uint (a 4-byte unsigned integer) all take up 4 bytes of memory. This likely means that they are all actually pointers to the actual data or that 4 bytes is some kind of minimum. (UPDATE: This is related to Flash Player storing some values as an integer. For more, see the article What is an int?.)
  • Dynamic functions are much more memory-intensive than methods, static or not. If you’re trying to save some memory, perhaps due to the constraints of a mobile device, you should make sure you don’t have a lot of these around. This may be the case if you use them as callbacks for many UI elements such as click handling for every item in a big list.
  • TextFields use over 1 KB of memory. While it’s unlikely that you’d have more than a handful on screen at once, consider all the ones that may be hidden. If you use MovieClips for each button state (up, over, down, etc.) and each has a TextField label, this may quickly add up. Also, it’s common to have all the screens of a UI in memory at once so beware of all the TextFields you have have around that are simply set to invisible or are not currently on the stage.
  • MovieClip uses only slightly more memory than Sprite, a relief
  • Shape uses far less memory than Sprite, which reinforces why you might like to use it instead of Sprite.
  • If you don’t need weak references and care more about memory savings than syntax benefits, consider Object over Dictionary for your mapping needs if you use a lot of them.

Overall I would say that the Flash Player is reasonably-efficient with memory usage for empty objects. Only in niche cases will you ever be called upon to reduce memory usage by reducing your data structure overhead, but those cases do exist. The size of an object can become very important when you’re storing tens of thousands of them for 3D meshes, targeting a tiny mobile device, or just trying to push the limits on a desktop machine.