おまじないである。
「もしかして、こうするといいんじゃないかな?」的な場当たり的情報である。 尚、V8のエンジンのGCの挙動を追っている訳では無く、体験的に感じた話である。
前提条件
- nodejsのv12での話。
- ES2018ぐらいでclassを書いてバンバンWebpackで1ファイルにつなげている。
- 内部構造的にはexportとimportが消えただけの状態
- 巨大データを扱いたい。
- 一応Chromeの開発者ツールで挙動は見たが・・・
- ぎょーみんぐPCと言うのはメモリが少なくてな・・・
- ぎょーみんぐPCは悪さが出来ないようにディスク容量も少ないのじゃ・・・
思ってたのと違う挙動
レキシカルスコープ宣言の変数、定数はスコープ抜けたらメモリ解放されるんじゃないの?
されませんでした。どうもGCが見に行って本当に使ってるやつ居ないよな?の確認が取れるまでメモリに乗っかってる。要するに何もしないとGCの時間がぐんぐん伸びて破綻します。
static宣言の定数(classの外に宣言する定数)は何時でも存在してるよね?
存在してません。代入後の評価が関数を挟んで数回に一回だと中身が空の場合が存在します。
オブジェクトプロパティを!!で評価するとundefinedの場合はfalseだよね?
trueの場合もあるよ? 何を言っているか分からねーと思うが、あの時、関数の引数に渡した値はtrueだったんだ。
で何をしたらいいの?
おまじない。おまじないを書くのです。
メモリ解放のおまじない
レキシカルスコープ変数、定数であってもスコープ内でやるとGCで引っかからなくなる。
// 配列の参照を消そう const a =[]; a.splice(0,a.length); //オブジェクトも消そう let keys = Object.keys(b); for(const key of keys){ delete b[key]; } keys.splice(0,keys.length); keys=null; //でかい文字列はletで宣言してnullを最後に入れる let veryLongString='~なんかやばい分量の文字列~'; veryLongString = null;
static宣言の定数は代入直後に参照しよう。
console.logに入れるのが簡単で安直だが、ログにゴミが溢れて困る。
const staticObj={}; const staticArray={}; class A{ constructor(inputs){ for(const input of inputs){ staticObj[input.key]=input.value; staticArray.push(input); } console.log(staticObj); //オブジェクトはこうするしか無いが・・・ console.log(staticArray.length); //配列は長さだけを見る。 } }
オブジェクトプロパティを!!で評価する場合は一旦定数に入れよう。
class A{ constructor(inputs){ // 変数に入れると扱いが変わる。 const isExecutable = !!inputs.isExecutable; this.execute(isExecutable); // ↓はどうなるか分からない場合がありうる。 this.execute(!!inputs.isExecutable); } execute(isExecutable){ if(isExecutable){ console.log('isExecutable!!!'); }else{ console.log('isExecutable?'); } } }
なんでこれを?
v8、v10の頃にはなかったんだけどなーがあって、急に出てこられるとかなり焦る。次はv14、v16なのである。さて次の最適化では何が変わるのか。