* メモリ管理#4
-(by [[K]], 2022.02.25)

** (0) もくじ
-aclライブラリバージョン2のメモリ管理について

-[1]AMemAlc0とAMemAlc1によるメモリ管理(メモリアロケータ)
-[2]ACleanによるオブジェクト管理の簡易化

** (1-1) メモリアロケータ
-acl2では、ヒープメモリのアロケータが改良されて以下のことができるようになった。
--AMemAlc0やAMemAlc1で取得したポインタには対応するidがあり、そのidは実行環境に依存しない。
--たとえばASLR(アドレス空間配置のランダム化)が有効な場合、アロケータが返すアドレスは、実行するたびに変わる。しかしそのポインタに対してidを取得すると、その値は毎回同じになる。OSが変わっても同じだし、CPUのアーキテクチャが変わっても同じになる。
--そしてid値からポインタを得ることもできる。
--これらの機能により何が実現するかというと、デバッグがやりやすくなるのではないかと思う。

-実例を使って説明する。
 void aMain(AComArg *ca0)
 {
     ABegin(ca1, c1, ca0);
     void *p;
     int i, alc0, ofs, id;
     AMemAlc0 *t28[28]; AMemAlc1_makeTable28(ca1, ca1->ta, t28, 0); // idを得るための下準備.
     for (i = 0; i < 7; i++) { // このループで7つのポインタを取得する.
         static int t[7] = { 1, 4, 1, 4, 2, 1, 3 };
         p = AMemAlc1_alc(ca1, ca1->ta, 8 << t[i], c1); // 16, 128, 16, 128, 32, 16, 64 バイトのメモリを取得.
         id = AMemAlc0_test3(ca1, t28, t28 + 28, p, &ofs, &alc0); // 取得したポインタのidを得る.
         printf("#%d: 0x%08x id=(%d,%d,%d)\n", i, (int) p, alc0, id, ofs); // それを表示.
     }
     AClean_out(ca1, c1); // これで7つのポインタは自動で解放される.
 }
-このプログラムを三度実行すると以下のようになる。
 #0: 0x007b36e8 id=(1,0,0)
 #1: 0x00610048 id=(4,0,0)
 #2: 0x007b36f8 id=(1,1,0)
 #3: 0x006100c8 id=(4,1,0)
 #4: 0x00614458 id=(2,0,0)
 #5: 0x007b3708 id=(1,2,0)
 #6: 0x00618868 id=(3,0,0)
 
 #0: 0x00b136f8 id=(1,0,0)
 #1: 0x006e0048 id=(4,0,0)
 #2: 0x00b13708 id=(1,1,0)
 #3: 0x006e00c8 id=(4,1,0)
 #4: 0x006e4458 id=(2,0,0)
 #5: 0x00b13718 id=(1,2,0)
 #6: 0x006e8868 id=(3,0,0)
 
 #0: 0x006636f8 id=(1,0,0)
 #1: 0x00670048 id=(4,0,0)
 #2: 0x00663708 id=(1,1,0)
 #3: 0x006700c8 id=(4,1,0)
 #4: 0x00674458 id=(2,0,0)
 #5: 0x00663718 id=(1,2,0)
 #6: 0x00678868 id=(3,0,0)
--ASLRによってポインタは毎回違っているが、そのポインタから取得したidは毎回同じになっている。
--だからメモリ上に構造木などを作った場合、そのリンク先のポインタのidを見れば、ポインタがおかしくなっているかどうかや、前に見た時と同じところを指しているのかどうかを簡単に見分けられる。
--そしてこのidは環境に依存しないので、最初はWindows上で開発していたが途中からLinux上で開発しているような場合でも、idに関するメモは全部そのまま使えることになる。

-プログラムを改造して以下のようにすることもできる。前半は上記と同じになっている。
 void aMain(AComArg *ca0)
 {
     ABegin(ca1, c1, ca0);
     void *p;
     int i, alc0, ofs, id;
     AMemAlc0 *t28[28]; AMemAlc1_makeTable28(ca1, ca1->ta, t28, 0); // idを得るための下準備.
     for (i = 0; i < 7; i++) { // このループで7つのポインタを取得する.
         static int t[7] = { 1, 4, 1, 4, 2, 1, 3 };
         p = AMemAlc1_alc(ca1, ca1->ta, 8 << t[i], c1); // 16, 128, 16, 128, 32, 16, 64 バイトのメモリを取得.
         id = AMemAlc0_test3(ca1, t28, t28 + 28, p, &ofs, &alc0); // 取得したポインタのidを得る.
         printf("#%d: 0x%08x id=(%d,%d,%d)\n", i, (int) p, alc0, id, ofs); // それを表示.
     }
     AClean_out(ca1, c1); // これで7つのポインタは自動で解放される.
 
     for (;;) { // idを入力してポインタを得る.
         char s[1000];
         printf("\n>");
         fgets(s, 10000, stdin);
         if (strncmp(s, "exit", 4) == 0) break;
         sscanf(s, "(%d,%d,%d)", &alc0, &id, &ofs);
         p = ((char *) AMemAlc0_test2(ca0, t28[alc0], id)) + ofs; // id値からポインタを得る.
         printf("%08x\n", (int) p);
     }
 }
-こうすると

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS