SSブログ

SilentC のメモリ管理をあばく [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

以前、SilentC のメモリ管理をのぞくでヒープ領域の使い方について少しのぞいてみましたが、管理領域が何を意味しているのか判然としませんでした。 その後、すっきり謎が解けたのでレポートします。

ヒープは線形リストである

HeapMemoryAllocation.png

メモリ領域の概要は、この図のようになっています。 ヒープ領域の先頭は、 0x20007DBC 番地にある HeapStart というポインタで示されています。 ヒープ領域は、任意の個数のブロックに分割されており、それぞれのブロックの最初の4バイトに管理情報が入っています。

4バイトの管理情報の最初の2バイトは、そのブロックのサイズを4バイト単位で示しています。 ブロックは、隙間無く配置されるので、この2バイトは事実上次のブロックへの相対アドレスを示すポインタとして機能します。 そして、管理情報後半の2バイトは、そのブロックで実際に使用されている領域のサイズを4バイト単位で示しています。 このような構造になっているため、ひとつのブロックには、ひとつの使用中領域とひとつ以内の未使用領域が存在することになります。

ヒープ領域の最後のブロックの管理情報には、 0 が書き込まれていて、線形リストの終端をあらわしています。

メモリの割り当て状況を調べる

管理情報の意味が判ったので、ヒープ領域の割り当て領域と未使用領域の計算させるプログラムを作成しましょう。 と、思ったのですが、ヒープ領域は時々刻々と変化しており、しかも SilentC インタプリタ自身がヒープを使用して作業をしているので、 SilentC のプログラムでヒープを調べるわけにはいきません。 そこで、ユーザ・ドライバの出番となります。

#include "support_common.h" /* include peripheral declarations and more */
#include "silentmoon.h"

uint32 *HeapStart @ 0x20007DBC;

//
// VECTOR #0 : main
//
uint32 main(uint32 arg) {
  #pragma unused(arg)
  uint32 size;
  uint32 *result;
  uint32 *p;
  
  result = MemoryAlloc(16);
  MemClear(result, 16);
  // result[0] (nBlocks)   Number of memory blocks
  // result[1] (allocSize) Total allocated memory size
  // result[2] (usedSize)  Total used memory size
  asm { // Disable interrupts
    move.w        #0x2700,sr
  }
  p = HeapStart;
  while (*p) {
    result[0]++;
    size = (*p >> 16);
    result[1] += size * 4;
    result[2] += (*p & 0xFFFF) * 4;
    p += size;
  }
  asm { // Enable interrupts
    move.w        #0x2000,sr
  }
  return (uint32)result;
}

//
//  Jump table for vectors
//
__declspec(jump_table)
asm void jump_table(void) {
  jmp main      // Driver #0   
}

プログラムの実行中にヒープの割り当てや開放が行われると、管理情報に矛盾が生じるので、プログラム実行中は割り込みを禁止しています。

このユーザ・ドライバは、配列へのポインタを返します。 配列のそれぞれの要素には、ブロック数、総ブロック容量、総使用容量の三つの値が入っています。 また、この配列は、ユーザ・ドライバ自身が MemoryAlloc 関数で割り当てています。

この配列を受け取って、結果を表示させる作業は、 SilentC のプログラムにやらせます。

main() {
  long *result = UserDriver(0);
  PrStr("BLOCKS    =");PrNum(result[0]);PrStr("\r\n");
  PrStr("ALLOCATED =");PrNum(result[1]);PrStr("\r\n");
  PrStr("USED      =");PrNum(result[2]);PrStr("\r\n");
  MemoryFree(result);
}

ユーザ・ドライバ内で配列を割り当てているので、使い終わったら、開放してやります。 このプログラムを実行すると、それぞれの値が表示されます。

OK
run
BLOCKS    =29
ALLOCATED =11712
USED      =11304
OK

このプログラムを実行した時には、29個のブロックが11712バイトにわたって割り当てられていました。 そのうち、実際に使用されているのは、11304バイトで、差分の408バイトに管理情報と未使用領域が存在するというわけです。

OK
MemoryAlloc(1024)

OK
run
BLOCKS    =30
ALLOCATED =12740
USED      =12328
OK

ここで、1024バイトの領域を新たに割り当てると、1028バイトのブロックがひとつ割り当てられ、使用されている領域が1024バイト増加したことがわかります。

プロジェクト・アーカイブ

ユーザ・ドライバのプロジェクトは、これを CFCQ08.zip という名前で保存すると再現できます。

参考文献

Interface (インターフェース) 2008年 12月号 [雑誌]

Interface (インターフェース) 2008年 12月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/10/25
  • メディア: 雑誌
Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。