アプリ終了時のMemoryBlockCountとMemoryBlockSizeの値が整合しない

アプリ終了時のMemoryBlockCountとMemoryBlockSizeの値が実際のカウントと整合しない.⇒ゴミ箱の廃棄をCouplingの削除の後に実行するようにした.ゴミ箱はCouplingの生成に先立って生成されているので,この方が筋が通っている.また,ゴミ箱とNringが存続していないと,メモリの使用状況が正確に把握できない.この変更を行ったことで,TRASHCAN:CheckWasteCountでも不整合が検出されるようになった.オブジェクトのカウントで32の差異が発生している.

この差異がCouplingの削除によって発生していることは明らかだ.つまり,この間に32個のオブジェクトが紛失していることになる.おそらく,これらはフロート化されたまま放置されているものと思われるが,そうではないかもしれない.フェーズをENDOFAPPLICATIONに切り替えるのをゴミ箱廃棄直前まで延期してこのエラーは解消した.

★ThrowCan 前 totalblock=0 totalsize=0 MemoryBlockCount=10037 MemoryBlockSize=8098118 TotalBlockCount=10037 TotalBlockSize=8098118

★ThrowCan 後 totalblock=0 totalsize=0 MemoryBlockCount=1 MemoryBlockSize=1180 TotalBlockCount=10037 TotalBlockSize=8098118

ThrowCan後に残っているMBCount=1, MBSize=1180とはゴミ箱のことだが,なぜこれが残ってしまうのかはよく分からない.⇒NODULE:operator deleteが呼び出されていない.強制的にNODULE::operator deleteを実行してやれば確かに消える.なぜCANだけがこのような動作になるのか?その理由が分からない.ゴミ箱TRASHCANは

class TRASHCAN : public ARRAY<MAXTRASHCAN>
class ARRAY : public nodule
class nodule : public NODULE {
static TRASHCAN *CAN; // ゴミ箱(廃棄オブジェクト分別収集)

のように定義され,メモリ上では

TRASHCAN *nodule::CAN = NULL; // ゴミ箱(廃棄オブジェクト…

のように配置されている.通常のオブジェクトは一度ゴミ箱に入ってから最終処分される.ゴミ箱自身はゴミ箱に入っていないということが影響しているのだろうか?ゴミ箱はNringに入っているか?⇒入っている.ゴミ箱廃棄直前ではNringにはこれしか入っていない.TRASHCAN:ThrowCanとdelete CANは別々に実行されている.

delete CAN

を実行したとき,NODULE::operator deleteが実行されないという点を除けば,すべての動作が整序している.CANに特異な点があるとすれば,noduleクラスの静的メンバーになっているという点だが,静的とは言え,ただのポインタなので中身のオブジェクトの生成・削除とは関わりがない…何かコンパイラが誤動作しているか,誤認しているのではないかという気がするのだが,おそらく,CANをNODULEの静的メンバーにしてしまえばこういうことは起きないのではないかという気もする.試してみよう.一度バックアップを取ってから…

その前にこのシステムがゴミ箱がなくても動作することを確認しておいた方がよいのではないか?USERECYCLESYSTEMというオプション(SPECIFICATION)はあるが… ⇒ゴミ箱がなくても動作には支障はないが,MemoryBlockCount=118005 MemoryBlockSize=25116470が丸残りになってしまう.現物はdeleteでメモリからは解放されているはずなので,残っているのはただの数字と思われるが…

この数字はnewで生成されたすべてのオブジェクトを含んでいる.つまり,カウントがまったくデクリメントされていない.ということはおそらく,NODULE:operator deleteが一度も実行されていないことを意味すると思われるのだが… どう考えればよいのだろう?

どうもこれは思ったより難しい問題であったような気がする.「ゴミ箱を生成しない」システムでアプリ終了しようとしたら,ReleaseReflistでエラーが発生した.NODULE::operator []が動作しないというエラーだ.対象ノードはすでに削除されているので,NODULEの仮想関数テーブルが潰れている.参照リスト管理ではこれまでオブジェクトの生死に関わりなく参照管理を行うという方針で進めてきているが,それもこれもゴミ箱のようなシステムがあったお陰と言ってもよい.つまり,nodule::operator deleteで寸止めしているため,仮想関数テーブルが辛うじて使える状態になっていたのだろう.

オブジェクトの生死を問わないというのは参照リスト管理に限った話ではない.UNDOもそれがなければ成立しない.削除されたオブジェクトを復活させようという話なのだから… 従って,ZTではNODULE:operator deleteが作動しないというのがノーマルであり,作動しているとすればそれは例外であると考えなくてはならない.NODULE:operator deleteが作動する条件というのはあまりはっきりしないが,おそらく,「一度deleteされ,もう一度newによって再生されたオブジェクト」なのではないか?⇒これは確認してみなければ分からない.

いずれにしても,nodule::operator deleteの中からNODULE::operator deleteを実行することの可否は,少なくともこのシステムでは死活問題だ.死者の延命・復活という手段がなければZTシステムは成立しない.ただし,参照管理リスト上にすでに死亡したオブジェクトが入っているというのは少しおかしいような気がする.なぜこんな状態になっているのかということをまず,先に調べた方がよいと思う.そのノードはどこで死んだのか?そのノードを参照するリンクが残っているのはなぜか?

障害が起きているノードは#74のMARGBOXだ.このノードはEraseTreeViewの中で削除されている.CleanSlotは実行されているが,参照管理に使っている特殊スロットは対象外で,参照リストには12個も参照が残っている.しかし,ReleaseReflistでMARGBOXの参照リストを削除する段ではすでにリスト要素はゼロになっている.つまり,問題は死亡したノードに参照リストが残っているという点だけだ.しかし,これは仕様であり,譲ることはできない.

従って,結論的には「nodule::operator deleteの中からNODULE:operator deleteを実行するという解決策はない」とするしかない.NODULE::operator deleteでやっていることは以下の一行だけだ.

if (!nptr->Shadow && !nptr->LIFE && (INDELETEPHASE || !nodule::CAN)) freeblock::_delmem(nptr);

これをnodule::operator deleteで実行すればよいというだけの話なのではないか?⇒いや,結構難しい.ThrowCanでゴミ箱のオブジェクトをdeleteしようとしてもできない.フローでは_delmemをパスしているので,メモリ上には残っているし,仮想関数テーブルも活きているようだが delete wasteが実行できない.おそらく,nodule::operator deleteを再実行することが禁止されているのだろう.つまり,nodule:operator deleteとNODULE::operator deleteの2段構成はどうしても不可欠ということのようだ.

「死亡したノードに参照リストが残っているという点」という点をもう少し考えてみよう.本来死亡したノードへの参照はデストラクタの中ですべてクリアされるというのが本筋であり,参照カウントがゼロになったノードでは参照リストを削除することができるとすれば,通常なら~noduleで参照リストを解放できるはずだ.⇒うまくいった!~noduleで参照カウントが残っているオブジェクトは存在しない.従ってすべての参照リストはその時点で削除される.⇒もう一度,「ゴミ箱なしの動作を確認@20201214」を試してみよう.

今回はnodule::operator deleteの中から直接NODULE::operator deleteを呼び出すのではなく,処理の対象を限定して,Shadowを持たないノードのうち,ゴミ箱に入らないものでかつLIFEが空となっているものだけを_delmemするようにして動作するようになった.ただし,一つだけ問題がある.ThrowCanを実行後にはMemoryBlockCount=0 MemoryBlockSize=0のようにきれいにクリアされているが,resetNringの手前でMemoryBlockCount=-1 MemoryBlockSize=-156になる.⇒理由は明らかだ.その前にrootnodeを削除しているためだ.

rootnodeにはNODULEのメンバーのnodule nullpointが入っている.このオブジェクトはnodule クラスの内部オブジェクトだが,静的メンバーでnewで生成されたものではないので,_delmemする必要はない.どこでそれを判断すればよいか?MemoryBlockCountは_delmemで更新しているので,ここでゼロ復帰でよいのではないか?このオブジェクトがnullpointであるということは,snum=0であることで判定できる.また,ntype=NOTAUTODELETEであることからも識別できる.⇒OKだ.かなりクリーンなイメージに近づいてきた.

UNDOシステムはゴミ箱がなくても動作しなくてはならない.確認しておこう.⇒ReferenceControlで参照カウントと参照リストの不一致が発生した.ゴミ箱を復旧して,MemoryBlockCountとMemoryBlockSizeが実際と合わないという事象が復活してしまった.ファイルを開いて終了では発生しないので,これまで見過ごされていた可能性はある.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA