When getSize() Lies
flash.sampler.getSize()
is a handy tool for figuring out how much memory a class instance uses. However, it is often flat-out wrong. Today’s article tries it out on a variety of classes to find out which ones it works on and which ones it doesn’t.
The following test app creates two instances of each class. The first is designed to be as close to an “empty” version as possible. For example, an Array
with no elements. The second is designed to be big enough that getSize
would tell us it’s bigger. For example, an Array
with 9 elements.
The following classes were tested:
XML
String
Object
Vector
Array
RegExp
BitmapData
IndexBuffer3D
VertexBuffer3D
Texture
Here’s the source code for the test app:
package { import flash.display.*; import flash.display3D.*; import flash.display3D.textures.*; import flash.utils.*; import flash.text.*; import flash.sampler.*; import flash.events.*; import flash.system.*; public class GetWrongSize extends Sprite { private var logger:TextField = new TextField(); private function row(...cols): void { logger.appendText(cols.join(",") + "\n"); } public function GetWrongSize() { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; logger.autoSize = TextFieldAutoSize.LEFT; addChild(logger); if (!Capabilities.isDebugger) { row("This app requires a debug Player"); return; } var stage3D:Stage3D = stage.stage3Ds[0]; stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3D); stage3D.requestContext3D(); } private function onContext3D(ev:Event): void { var stage3D:Stage3D = stage.stage3Ds[0]; var context3D:Context3D = stage3D.context3D; var xmlEmpty:XML = new XML(); var xml:XML = <xml><something/><stuff/><things/><more/><data/></xml>; var strEmpty:String = ""; var str:String = "abunchoftextisinthisstringandnowthereisevenmore"; var objEmpty:Object = {}; var obj:Object = { key:123, thing:456, stuff:789, other:000 }; var vecEmpty:Vector.<int> = new <int>[]; var vec:Vector.<int> = new <int>[123,456,789,000,111,222,333,444,555]; var arrEmpty:Array = []; var arr:Array = [123,456,789,000,111,222,333,444,555]; var regexEmpty:RegExp = new RegExp(""); var regex:RegExp = new RegExp("[abcdefghijklmnopqrstuvwxyz0123456789]"); var bmdEmpty:BitmapData = new BitmapData(1, 1); var bmd:BitmapData = new BitmapData(64, 64); var ibEmpty:IndexBuffer3D = context3D.createIndexBuffer(1); var ib:IndexBuffer3D = context3D.createIndexBuffer(1024); var vbEmpty:VertexBuffer3D = context3D.createVertexBuffer(1, 4); var vb:VertexBuffer3D = context3D.createVertexBuffer(1024, 4); var texEmpty:Texture = context3D.createTexture(bmdEmpty.width, bmdEmpty.height, "bgra", false); var tex:Texture = context3D.createTexture(bmd.width, bmd.height, "bgra", false); texEmpty.uploadFromBitmapData(bmdEmpty); tex.uploadFromBitmapData(bmd); row("Object", "Empty Size", "Size"); row("XML", getSize(xmlEmpty), getSize(xml)); row("String", getSize(strEmpty), getSize(str)); row("Object", getSize(objEmpty), getSize(obj)); row("Vector", getSize(vecEmpty), getSize(vec)); row("Array", getSize(arrEmpty), getSize(arr)); row("RegExp", getSize(regexEmpty), getSize(regex)); row("BitmapData", getSize(bmdEmpty), getSize(bmd)); row("IndexBuffer3D", getSize(ibEmpty), getSize(ib)); row("VertexBuffer3D", getSize(vbEmpty), getSize(vb)); row("Texture", getSize(texEmpty), getSize(tex)); } } }
And here are the results:
Object | Empty Size | Size |
---|---|---|
XML | 120 | 608 |
String | 40 | 40 |
Object | 80 | 176 |
Vector | 144 | 160 |
Array | 168 | 208 |
RegExp | 112 | 112 |
BitmapData | 160 | 16480 |
IndexBuffer3D | 40 | 40 |
VertexBuffer3D | 40 | 40 |
Texture | 424 | 424 |
Run the test app (debug player required)
getSize
worked on these five classes:
XML
Object
Vector
Array
BitmapData
But it didn’t on these five classes:
String
RegExp
IndexBuffer3D
VertexBuffer3D
Texture
It’s not too surprising that GPU-side memory objects like IndexBuffer3D
, VertexBuffer3D
, and Texture
didn’t report a size change, but it is quite surprising that such fundamental CPU-side memory objects like String
and RegExp
failed to show an increase in memory usage. After all, both of these classes have built-in language support such as "literal strings"
, automatic calling of toString()
, and /regexp literals/
.
Again, getSize
is very useful in circumstances where it works. But be careful to check that the class you’re using it with is supported. The documentation does not warn you of this, so you’ll need to explicitly check every class you want to test.
Spot a bug? Have a question or suggestion? Post a comment!
#1 by henke37 on May 26th, 2014 ·
It is supposed to work on Strings. The master string system just risks confusing simple code, the getMasterString function is needed to resolve that mess.
#2 by jackson on May 26th, 2014 ·
Apparently, it doesn’t work on
String
. I double-checked just now and neitherstr
norstrEmpty
have a masterString
that would be hiding the data.#3 by Antoine on May 26th, 2014 ·
Regarding the IndexBuffer3D / VertexBuffer3D, i don’t see why their size would vary based on the integers provided to the
create...()
methods. Not matter the value of the input integer, shouldn’t the allocated memory be the same from the AS3 runtime point of view ?For the texture, I’m suprised by the size of the Texture object itself. However, since it doesn’t “own” the BitmapData object, it makes sense to me that the size stays the same no matter the size of the bitmap. However developers should take care of cleaning the underlying memory used by the texture with the
dispose()
method.Would be curious to see how the
getMasterString()
function would reflect on the tests results for String/RegExp.#4 by jackson on May 26th, 2014 ·
createIndexBuffer takes the number of indices you want the buffer to hold as its first parameter. You can’t pass 0, so I passed 1 for the empty case. For the non-empty case, I passed 1024 which should consume at least a couple KB of memory.
As mentioned in the article and concurring with your point, this memory is sort-of “external” to the AS3 runtime. The
IndexBuffer3D
is probably just holding a hardware resource handle for memory allocated outside the Flash Player by a system like OpenGL. This memory may even be consumed on the GPU rather than the CPU’s main memory. But it may be on the CPU for a variety of reasons. This includes the case where a software rasterizer is used as a fallback when hardware support isn’t available or requested.The same points go for vertex buffers and textures: they’re all “external” to the Flash Player.
As for
getMasterString
, I checked and neitherString
has one.