JDBな人生  専門的なことから日常的なことまで~ まぁ自由きままに書いていきます。
2017年06月 / 05月<< 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 >>07月

アクセスランキング

[ジャンルランキング]
コンピュータ
368位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
52位
アクセスランキングを見る>>

JavaScriptでのクラスの実装とメモリ使用量の違い

最近、とある本を読みました。
JavaScript: The Good Partsという本です。

Douglas Crockford (著), 水野 貴明 (翻訳)
JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス


主にはJavaScriptのコード記述のスタイルについての本です。本の感想はさておき(とても勉強になりましたが)、本の五章目に継承の方法についての記述があります。

続きは以下から。

more...

その中では、“クラス”の実装の方法について、オブジェクトのprototypeプロパティを利用する行う擬似クラス型とプロトタイプ型、コンストラクタ内で新しく生成したオブジェクトにメソッド・プロパティを追加していく関数型が紹介されています。(継承についてはここでは触れません)

※記事中では“クラス”、“インスタンス”、“メソッド”、“プロパティ”といった表現が適切でない場合もあるかもしれませんが、ややこしくなるのですべて統一します。

簡単にまとめるとこんな感じです。

//擬似クラス型
var TestClass = function(){};
TestClass.prototype.publicMethod = function(){
    alert("public method");
};
TestClass.prototype.publicProperty = "public property";

var obj = new TestClass();


//プロトタイプ型
var TestClass =
{
    publicMethod: function(){
        alert("public method");
    },
    publicProperty: "public property"
};

var obj = (function(o){
    var F = function(){};
    F.prototype = o;
    return new F();
})(TestClass);
//本ではObject.Createに無名関数部分を定義


//関数型
var testClass = function(){
    var that = {};
    var privateProperty = "private property";
    var privateMethod = function(){
        alert("private method");
    };
    that.publicMethod = function(){
        alert("public method");
        alert("private property: " + privateProperty);
    };
    that.publicProperty = "public property";
    return that;
}

obj = testClass();

擬似クラス型とプロトタイプ型ではプライベートなメソッドやプロパティを定義することができませんが、関数型ではそれが可能です。

(念のため解説)
JavaScriptのスコープの性質について。…別の章から引用

スコープに関して良いニュースもある。ある関数内で別の関数が定義されている場合、内部の関数は、外側の関数で定義された変数やパラメータ(中略)にアクセスできるという点である。

testClass関数の実行を終えた時点で、privateMethodやprivatePropertyは消滅する…ように見えますが、実際には、publicMethodを実行するときに、privatePropertyにアクセスすることができます。(publicMethodは、その外側の関数(testClass関数)内で定義されている変数(privateProperty)にアクセスすることができます)
しかし、それ以外の場所では、privatePropertyやprivateMethodの参照を得ることはできないため、外部から任意に実行することはできなくなるというわけです。


と、ここまでが前置きです。

本題はここから…(ここからは本とは無関係な内容です)

プライベートなメソッドやプロパティを定義することのできる関数型ですが、欠点もあります。それは、同じメソッドやプロパティを複数のオブジェクトがインスタンスの数分保持するという点です。擬似クラス型やプロトタイプ型であればprototypeにまで辿っていけば使うことのできるメソッドですが、関数型ではそれぞれのオブジェクトが一つ一つ保持することになります。(全く同じ動作をしますが実体・参照は別物です)

その結果、何千という数のオブジェクトを生成すると、メモリを大量に消費することになります。

そこで、1000個の簡単なメソッドを定義したクラスのインスタンスを1000個~5000個生成したときのメモリ使用量を測定してみました。(開いているタブのメモリ使用量のみ測定)

測定に使用したコード
mem.js

こんな感じ。縦軸はメモリ使用量[MB]、横軸はオブジェクト(インスタンス)の数(1000が基準)です。
130629_both_20130630010045.png

関数型では、オブジェクトの数を1000,2000と増やすと、数十MB単位で使用量が増えることがわかります。
つまり、メモリの浪費につながるということです。

そこで解決策…を考えたんですが、結論としては、「大量のインスタンスを生成する必要のあるものは関数型で記述しない」ということです。(ここでの大量というのは1000とか10000とか100000とかです)
「資源の有効利用を優先」するか、「セキュリティを優先」するかの使い分けです。
#まあそんなに大量な数になることがどれだけあるかという話にもなりますが…

#JavaScriptの設計はC++やJavaなどの他のオブジェクト指向言語と比べてだいぶ癖がありますが、慣れてくるとなかなか面白いものですね
 


 
   JavaScript    TB(0)    CM(0)    EDIT    ページ↑

コメント投稿


 管理者だけに表示

コメント

トラックバック

この記事へのトラックバック:

プロフィール

JDB Luigi

Author:JDB Luigi
どこにでもいるようなありふれた人間・・・という訳でもなく、かと言って怪しい宗教を信仰する変人という訳でも無い。

基本的に掲載しているコード等は煮ていただいても焼いていただいても結構ですが、利用は自己責任にてお願いいします。
また、バグ・アドバイス等もしあればよろしくお願いします。