2016-04-14 5 views
0

私はC言語で単純なメモリプールを構築しました。このプールにメモリブロックを実装する機能も実装しました。Cメモリプールのメモリブロックのデフラグ

メモリブロック自体は非常に単純で、フリーフラグとサイズプロパティを持つ二重リンクリストです。

私が今しようとしているのは、割り当てられた(フリー== 0)ブロックがプールの先頭にあり、割り当てが解除されたブロックになるように、メモリプールへのポインタをとり、メモリブロックをデフラグする関数を作成することですプールの終わりに向かっています。例えば

、私は私のデフラグ機能と呼ばれる前にメモリのブロックは、このような構造があった場合:

Block Size: 25 (41 w/ header), Free: 1 
Block Size: 100 (116 w/ header), Free: 0 
Block Size: 25 (41 w/ header), Free: 1 
Block Size: 100 (116 w/ header), Free: 0 
Block Size: 100 (116 w/ header), Free: 0 
Block Size: 54 (70 w/ header), Free: 1 

はその後、私の関数を呼び出した後、ブロックはそのように配置されることになります。

Block Size: 100 (116 w/ header), Free: 0 
Block Size: 100 (116 w/ header), Free: 0 
Block Size: 100 (116 w/ header), Free: 0 
Block Size: 25 (41 w/ header), Free: 1 
Block Size: 25 (41 w/ header), Free: 1 
Block Size: 54 (70 w/ header), Free: 1 

私はすでに関数をビルドしようとしましたが、正しいブロックを動かすことで問題に遭遇しましたが、関数が呼び出された後に出力されるようです。

Block Size: 100 (116 w/ header), Free: 0 
Block Size: 25 (41 w/ header), Free: 1 
Block Size: 100 (116 w/ header), Free: 0 
Block Size: 1744830464 (1744830480 w/ header), Free: 21 

機能が誤った操作を実行している場所がわからないので、うまくいけば、誰かが私にこの問題を明らかにすることができます。

私のデフラグ機能:

void defragment(Pool* pool) 
{ 
    if(pool && pool->root) 
    { 
     Block* current = pool->root; 

     while(current) 
     { 
      if(!current->free) 
      { 
       Block* current_prev = current->prev; 

       if(current_prev && current_prev->free) 
       { 
        Block* prev_prev = current_prev->prev; 
        int new_block_size = current_prev->size; 

        Block* moved_current = memmove(current_prev, current, sizeof(Block) + current->size); 

        if(!moved_current) 
        { 
         printf("couldn't move memory\n"); 
        } 
        else 
        { 
         Block* new_block = initBlock((((char*)moved_current) + sizeof(Block) + moved_current->size), new_block_size); 
         new_block->prev = moved_current; 
         new_block->next = moved_current->next; 

         moved_current->prev = prev_prev; 
         moved_current->next = new_block; 

         if(prev_prev) 
         { 
          prev_prev->next = moved_current; 
         } 

         current = moved_current; 
         continue; 
        } 
       } 
      } 

      current = current->next; 
     } 

     //Join Contiguous Blocks 
    } 
} 

initBlock関数の呼び出しは、ちょうどその指定されたサイズに真の自由財産とサイズプロパティを設定し、ブロック構造として扱い、メモリアドレスを取得します。

私はGCCコンパイラを-std = C99フラグとともに使用しています。

+2

割り当てられたブロックの所有者は、移転後どのようなことになりますか? –

+0

@WeatherVane現時点では、所有者が保持しているポインタがuniの代入のために保持されている必要はありません。割り当ての中間ディレクトリを持ち、ポインタを持続させると、より高いマークが得られますが、それは低いマークの要件ではありません。 –

+2

defraggerは、ユーザーがメモリポインタをどこに配置したかを知らないため、更新できません。確かに、未使用領域のデフラグのみが可能です。ハードディスクを最適化するときと同じように、開いているファイルは移動できません。 –

答えて

1

ブロックペアをスワップした後、次のブロックのprevフィールドを更新していないようです。したがって、次のブロックに進み、前のブロックが空いているかどうかを確認すると、ゴミにアクセスすることになります。あなたは、

if (newblock->next) 
    new_block->next->prev = new_block; 

上記のelseのようなものが必要です。

その他の懸念

  • あなたのブロックはすぐに連続しており、プール内の順番になっていない場合、これがひどく誤動作します。プール全体が1つの連続したmemeoryのブロックであることを確認しているかもしれませんが、他のルーチンが何かを並べ替えると問題が発生する可能性があります。妄想プログラミングのために、これらの不変量が確実に侵害されていないことを確実にするためにアサートすることをお勧めします。
  • プールに任意の外部のポインタは、あなたが(あなたがいるように見える)奇数サイズのブロックを持っている場合は、あなたが最高の状態で非効率的である非整列のポインタを、買ってあげると、最悪はクラッシュすることがあります。この操作
  • 後にゴミになります。
  • プールにポインタを含む固定サイズのハンドルの関連配列を持つと説明しているようにプールには普通ですが、空きでないブロックを移動するたびに、プール内のポインタを更新する必要があります。対応ハンドル。ハンドルには、移動するブロックを禁止する「ロック」フラグが含まれている場合もあります。その場合は、そのフラグをチェックし、ロックされていないブロックのみを移動し、ブロックを移動すると隣接しないブロックに移動する必要があります。これにより、上の最初の点で問題が発生する可能性があります。
関連する問題