flash.sampler っていうパッケージを最近知ったので使ってみたかっただけです。
メモリ管理のコツとかそういう tips 的なことは一切書いてないですごめんなさい。。
注) 32bit CPU での検証結果です
flash.sampler.getSize() で各クラスのサイズを調べてみました。
[as]
import flash.sampler.getSize;
// トップレベルのコアクラス (Error のサブクラスなどは除く)
var top_level:Array = [Array, Boolean, Date, Error, Function, int,
Namespace, Number, Object, RegExp, String, uint,
Vector.
for(var i:int=0; i きっと4バイト境界でメモリがアラインされてると思うのですが、 せっかくなので他のパッケージの主要(?なクラスも測ってみました。 Sound と TextField が一桁大きいです。 次に、ユーザー定義クラスについて。 // Struct クラスのサイズを調べる trace(getSize(new Struct()); // -> 20 なるほど。一要素ずつちまちまとアロケートしないってことですね。 ループの長さに比例した大きな単位でメモリを確保するようになっているようです。 Vector には fixed プロパティというものがあり、コンテナの長さを固定できるようになっています。 また、fixed を true にすると、コンテナのサイズは “参照のサイズ×要素数” ちょうどになります。 せっかくなので ByteArray でも試してみます。 これ ByteArray はページ単位で管理してるってことですかね。 インデックスの 1024 にアクセスしても返される値は変わりませんでしたが、 次に、最初に疑問を投げた Number型 が 4 を返すことについて。 なんと、再度小さな値を入れると4bytesにリアロケートされます。 他にもいろいろ調べられそうですが、今回はこの辺で。 flash.sampler パッケージを使ってオレオレプロファイラ作るのも楽しいかもしれません。
Function の値が不思議なのと、Number が4なのはどうして?
というかそもそも flash.sampler.getSize() で戻ってくる値は一体なんなのか。。
[class Bitmap] : 232
[class ByteArray] : 92
[class Camera] : 44
[class ColorTransform] : 80
[class Dictionary] : 56
[class Loader] : 304
[class Matrix] : 64
[class Matrix3D] : 84
[class MovieClip] : 436
[class Point] : 32
[class Shape] : 232
[class SimpleButton] : 248
[class Socket] : 80
[class Sound] : 8384
[class Sprite] : 400
[class TextField] : 1288
[class TextFormat] : 104
[class Rectangle] : 48
[class RegExp] : 64
[class URLLoader] : 60
[class URLRequest] : 44
[class URLStream] : 72
[class URLVariables] : 40
[class Video] : 240
[class XMLSocket] : 104
以下のようなメンバを持たないクラスのサイズを調べます。
[as]
public class Struct {
public function Struct() {
}
}
trace(getSize(new Struct()); // -> 16
[/as]
メンバを持つ場合は?
[as]
// Sprite のメンバを持つクラス
import flash.display.Sprite;
public class Struct {
private var a:Sprite;
public function Struct() {
}
}
[/as]
Sprite型のメンバを持っていても 416 とは返ってきません。
この場合、保持するデータ型自体のサイズではなく参照のサイズが加算されています。
なんとなくわかってきました。
次はコンテナに詰め込んで試してみます。
[as]
var struct_arr:Array = [];
for(var i=0; i<10; i++) {
struct_arr[i] = new Struct();
}
trace("size: ", getSize(struct_arr) - getSize([])); // -> size: 48
[/as]
あれ?40bytes じゃない?
trace をループの中に置いてみます。
[as]
var struct_arr:Array = [];
for(var i=0; i<10; i++) {
struct_arr[i] = new Struct();
trace("size: ", getSize(struct_arr) - getSize([]));
}
[/as]
size: 16
size: 16
size: 16
size: 16
size: 24
size: 24
size: 32
size: 32
size: 48
size: 48
じゃあ Vector は?
[as]
var struct_vec:Vector.
var vec:Vector.
for(var i:int=0; i<10; i++) {
struct_vec[i] = new Struct();
trace("size: ", getSize(struct_vec) - getSize(vec));
}
[/as]
size: 4
size: 8
size: 12
size: 20
size: 20
size: 28
size: 28
size: 40
size: 40
size: 40
(Array と Vector でルールは多少違うようですが)
ユーザ定義クラスではなく、int や Number でも同様でした。
気になる人は追試してみてください。
また、要素数100万のループでアロケートの回数を数えてみると、
Array:45回
Vector:57回
と、 Vector の方がアロケートの回数自体は多いという結果に。
fixed を true にするとアロケートの回数は当然インスタンス生成時の1回限りです。
この fixed の有無でたいした差は出ないという内容のエントリーを国内外でたくさん見ましたが、
何十, 何百万要素のループくらいになると、メモリのアロケートがループ後半ではあまり起きないため、
たいしたパフォーマンスの差が出なかったということなんでしょう。
つまり要素数100万の場合は40,000,000bytesです。
fixed を false にすると、ループ中は上述のようにまとまった塊でメモリを確保していくので、
新たなメモリを確保した瞬間にループを抜けると、必要のない領域までガメてしまうことになります。
これは結構大切な事だと思うので覚えておくといいかもしれません。
[as]
var struct_ba:ByteArray = new ByteArray();
var ba:ByteArray = new ByteArray();
for(var i:int=0; i<10; i++) {
struct_ba[i] = new Struct();
trace("size: ", getSize(struct_ba) - getSize(ba));
}
[/as]
size: 4096
size: 4096
size: 4096
size: 4096
size: 4096
size: 4096
size: 4096
size: 4096
size: 4096
size: 4096
ページ境界をまたいだアクセスが頻発すると大変なことになりそうです。
4096 にアクセスした瞬間にまたメモリをガメてきました。
ここでおもむろに、
getSize(struct_ba[1]) や getSize(struct_ba[1024])
とするといずれも 4 が返ってくることを確認。
なるほど、ByteArray と getSize() のことがわかってきました。
F-size さんで以下のようなエントリーを見つけました。
F-site | [AS3] プリミティブ型データとメモリ
どうやら4bytesで抱えきれない値を代入すると8bytesにリアロケートするようです。
[as]
var n:Number = 1;
trace(‘Number size: ‘,getSize(n));
n = Math.pow(2, 28);
trace(‘Number size: ‘,getSize(n));
n = 1;
trace(‘Number size: ‘,getSize(n));
[/as]
Number size: 4
Number size: 8
Number size: 4
これけっこうなコストだと思うのですが、、
Flashで大きな数値を扱うことは少ないからでしょうか、ちょっとわかりません。
あとはFlash本業の方に任せようと思いますwあわせて読む:
2 Thoughts