一般的なオブジェクトの寿命の管理モデルC++ではnewでオブジェクトを作ってdeleteで破棄していました。自動変数(スタック上にとられる変数)はスコープから抜けるときに自動でデストラクタが呼び出されていました。この自動変数の挙動は便利で分かりやすくて深刻なメモリリークバグも起こりにくいと思いますが、自分でnewして作ったオブジェクトについてはdeleteを呼び忘れたりしてメモリリークバグの大きな原因となっています。JavaではGC(ガーベージコレクション)を採用し、プログラマがdeleteしないでもいいようにしました。これは一見すると非常にかっこいいのですが、実際は処理系が未使用のオブジェクトをうまく検出できずにメモリリークしてしまったり(特に循環参照などが起こるとリークしやすい)、full-GCが始まるとプログラムがしばらくの間とまってしまう問題があります。GCは多くの場合ではプログラマを寿命管理から解放してくれます。そのせいでこれに配慮しないことに慣れてしまい、リークやfull-GCに悩まされ始めた時にどうしていいかわからなくて途方に暮れることになります。これはあまり教育的な仕様とは言えないでしょう。これらに対する比較的新しい方法として、autorelease方式があります。iOSのObjective-Cで使われています。これはとても良い方法だと思いました。KH-FDPLでも最初はこの方法をそのまま取り入れようと思っていたくらいです。autoreleaseしない場合に、retainやreleaseで参照カウンタを管理しなければいけません。その部分の難易度が従来と大差ないと思いました。ここで間違えればやはりメモリリークしてしまいます。最近のarcの仕組みを使うと、retainやreleaseを意識しなくても自動でかなりうまくやってくれるそうです。循環参照以外でリークすることはほとんどないそうです。KH-FDPLのオブジェクトの寿命の管理モデルKH-FDPLは参照カウンタを持ちません。結局こういうものをプログラマに管理させていると、永久にメモリリーク問題はなくならないと思うからです。短期間で作って壊すようなオブジェクトは、まさにautoreleaseと同じ方法で管理します。次回の回収時に回収されるプールがあるので、そこに登録するわけです。それより長く生き残るオブジェクトに関しては、どのプールに所属するかを「new時に」指定します。どんなプログラムも、最低一つのプールを持っていますし、関数呼び出しをすればそのたびにプールが作られます。それらの中のどのプールに所属するのかをnew時に指定すればいいのです。これにより、そのプールが回収されるときに必ずオブジェクトは回収されます。寿命を変更したくなれば、あとから所属するプールを変更すればいいです。それで問題ありません。プールを指定するなんて言うとややこしく聞こえますが、ファイルを作るときに所属パスを指定するのと同じくらいの感覚です。何も指定しなければ、次回回収プールがデフォルトで選ばれます(autorelease相当)。関数の戻り値用のオブジェクトは、次々回回収プールがデフォルトになります。そもそもオブジェクトを作るときが、もっともオブジェクトの寿命について考えているときでもあるのです。オブジェクトを作るときは、そのオブジェクトを何のために作るのかわかっていますし(目的)、だからいついらなくなるのかもわかっているのです。KH-FDPLはオブジェクトが基本的に永続性なので、メモリリークは非常に深刻です。こんなにリークさせない仕組みにこだわっているのです。KH-FDPLでリークを起こしてしまったら、それは再起動後にも残るので、放置していると永久に残ります。他の言語環境ならリークしても再起動すれば済みますが、KH-FDPLではそうは行かないわけです。自分でせっせとリークしたオブジェクトを特定して消していけばいいといえばそれまでですが、それよりはリークを起こさない仕組みを考えるほうが建設的だと思います。他の管理アルゴリズムは使えないのか?KH-FDPLは多様な言語を受け入れたいと思っています。GCが好きな人はGCのあるプログラミング言語を書きたいでしょうし、new-deleteモデルが好きな人はそういうプログラミング言語を書きたいでしょう。簡単なnew-deleteモデルから行きましょう。このモデルの言語では、オブジェクトをすべて一つのプールに所属させておいて、そのプールはアプリが終了するまで残るようにしておきます。これで勝手に消えることは一切なくなります。それで、delete命令が来たら、そのプールから個別に削除してやればいいだけです。いう動作をするバイトコードをコンパイラが生成すればいいだけです。GCの場合も同様です。GCスレッドは、プールの中のすべてのオブジェクトをスキャンすることができます。それで誰からも参照されていないオブジェクトを見つけたら、それを個別に削除すればいいだけです。[ここはかなり具体的なのでより詳しく知りたい人向け]new-deleteモデルは、「使わなくなったらdeleteしてください」というだけなので、管理さえできればうまくいくのは自明です。GCモデルも「誰からも参照されなくなったら勝手に消えます」というだけなので、やはりうまくいくのは自明です。KH-FDPLは、本当にそれでうまくいくの?と不安になるかもしれません。いうことで、詳しい解説を試みます。KH-FDPLでは、関数を呼ぶ直前に「スタックフレーム」という「データストア型オブジェクト」を作ります。イメージとしてはフォルダみたいなものを考えてください。これがプールになります。関数はローカル変数を使います。するとそれらのローカル変数はそのスタックフレームの中に作られていきます。することで他の関数の変数と名前が衝突する心配がありません。関数から抜けると、スタックフレームは削除されます(もしかしたらすぐには消さずに、次の関数呼び出しの直前に消されるかもしれない)。ローカル変数は消えることになります。関数が関数を呼び出した場合、スタックフレームの中にスタックフレームが作られて、そこが使われます。いう仕組みなので再帰とかでも大丈夫です。ローカル変数についてはこれで良いとして、それではそれ以外のオブジェクトはどうでしょうか。何か複雑なオブジェクトを作ってそれを返す関数、なんていうのはありふれたことです。この場合、そのオブジェクトを「どこに作るのか」を呼び出し元が指定します。何層にも重なったスタックフレームのうちのどれにするか、ということです。深いところのスタックフレームならそれだけ長い間消えずに残ることになります。やって長生きするオブジェクトを作った後なら、そのオブジェクトに対する参照がどれだけあちこちで作られても問題なしです。循環参照とかがあっても別にいいです。関数から抜けて、更に関数から抜けて、そうやって何段かの階層を抜ければ、そのタイミングでこのオブジェクトも消えます。「mainから抜けるまではずっとそのオブジェクトにアクセスしうる」という状況なら、mainのスタックフレームにオブジェクト作れらせればいいのです。それだけのことなのです。そもそもsubという関数が呼び出し元であるmainのスタックフレームを指定できるものなのでしょうか。子は親のスタックフレームにアクセスできていいのでしょうか?これは簡単に言えば、フォルダをさかのぼる「..」があってもよいのかということです。こんなものがあれば、どんどんさかのぼってやがてはルートにだどりつけてしまいます。これはセキュリティ上問題があります。・・・ということで、subは勝手にはmainのスタックフレームを指定できません。subはmainからスタックフレームを引数でもらっているのです。ここまでをまとめます。...}こんな感じになります。sub1が実際にオブジェクトを作っているところですが、その際にmainのスタックフレームを使っています。それを実現するために、main内の関数呼び出しでは引数にスタックフレームを指定していますし、sub0ではそれをリレーしています。カッコよくやるならこうだと思います。obj;}結果的に、sub1が作ったオブジェクトはmainのworkとして残ることになります。システムはmainを呼び出すにあたって@stackというフォルダを作り、そこをカレントにする。main()はさらに@stackというフォルダを作ってそこをカレントにした後、sub0()を呼び出す。sub0()はさらに@stackというフォルダを作ってそこをカレントにした後、sub1()を呼び出す。sub1()はカレントディレクトリにobjというフォルダを作って、その中にfooやbarを作っていく。sub1()でのreturn命令により、objは@retValにリネームされる。sub1()を抜けてsub0()に戻る。sub0()ではフォルダの階層を元に戻す。その上で@stack.@retValというオブジェクトをreturnValueにリネームする。@stackは次の関数呼び出しまでには消える運命なので、@retValをreturnValueにコピーする必要はなく、リネームで十分。リネームならオブジェクトのIDも変わらない。sub0()でのreturn命令により、returnValueは@retValにリネームされる。sub0()を抜けてmain()に戻る。main()ではフォルダの階層を元に戻す。その上で@stack.@retValというオブジェクトをworkにリネームする。