21

アラインされたメモリ ブロックの管理についていくつか質問があります。クロスプラットフォームの回答が理想的です。ただし、クロスプラットフォームのソリューションが存在しないことは確かなので、主に Windows と Linux に関心があり、(はるかに) 少ない範囲で Mac OS と FreeBSD に関心があります。

  1. メモリのチャンクを 16 バイト境界に整列させる最良の方法は何ですか? (私はmalloc()、少し余分なスペースを割り当ててから、適切に位置合わせされた値までポインターをバンプするという簡単な使用方法を認識しています。問題。)

  2. 単純な古い を使用しmalloc()、余分なスペースを割り当ててから、ポインターを正しく配置される場所に移動する場合、解放のためにポインターをブロックの先頭に保持する必要がありますか? (ブロックの中央へのポインターの呼び出しfree()は、Windows では実際に機能するようですが、標準が何を言っているのか、標準ができないと言っていても、すべての主要な OS で実際に機能するかどうか疑問に思っています。私はあいまいなDS9Kのような OSは気にしないでください。)

  3. これは難しい/興味深い部分です。整列を維持しながらメモリブロックを再割り当てする最良の方法は何ですか? malloc()理想的には、これは を呼び出し、コピーfree()してから古いブロックを呼び出すよりもインテリジェントなものになります。出来ればその場でやりたい。

4

7 に答える 7

20
  1. 実装に 16 バイトのアラインメントが必要な標準データ型がある場合 (long longたとえば)、malloc返されたブロックが正しくアラインされることは既に保証されています。C99 州のセクション 7.20.3The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object.

  2. によって与えられたのとまったく同じアドレスを に戻す必要があります。例外なく。そうです、元のコピーを保持する必要があります。freemalloc

  3. すでに 16 バイト アラインメントが必要な型がある場合は、上記の (1) を参照してください。

それを超えて、malloc標準では保証されていませんが、実装が効率のために16バイトで整列されたアドレスを提供することに気付くかもしれません。必要に応じて、いつでも独自のアロケーターを実装できます。

私自身、その上に次の構造を使用するmalloc16レイヤーを実装します。malloc

some padding for alignment (0-15 bytes)
size of padding (1 byte)
16-byte-aligned area

次に、malloc16()関数を呼び出しmallocて、要求されたよりも 16 バイト大きいブロックを取得し、整列された領域がどこにあるべきかを判断し、その直前にパディングの長さを置き、整列された領域のアドレスを返します。

の場合free16、指定されたアドレスの前のバイトを見てパディングの長さを取得し、そこから malloc されたブロックの実際のアドレスを計算し、それを に渡しfreeます。

これはテストされていませんが、良いスタートになるはずです:

void *malloc16 (size_t s) {
    unsigned char *p;
    unsigned char *porig = malloc (s + 0x10);   // allocate extra
    if (porig == NULL) return NULL;             // catch out of memory
    p = (porig + 16) & (~0xf);                  // insert padding
    *(p-1) = p - porig;                         // store padding size
    return p;
}

void free16(void *p) {
    unsigned char *porig = p;                   // work out original
    porig = porig - *(porig-1);                 // by subtracting padding
    free (porig);                               // then free that
}

の魔法の行はmalloc16p = (porig + 16) & (~0xf);アドレスに 16 を追加し、下位 4 ビットを 0 に設定し、事実上、次に低いアラインメント ポイントに戻します (+16これにより、maloc されたブロックの実際の開始点を過ぎていることが保証されます)。

さて、私は上記のコード下品だとは言いません。対象のプラットフォームでテストして、機能するかどうかを確認する必要があります。その主な利点は、醜いビットを抽象化して、心配する必要がないことです。

于 2011-02-21T01:22:56.657 に答える
1

最もトリッキーな要件は明らかに 3 番目の要件です。これは、malloc()/realloc()ベースのソリューションはrealloc()ブロックを別の配置に移動するための人質だからです。

mmap()Linux では、の代わりに で作成された匿名マッピングを使用できますmalloc()。によって返されるアドレスはmmap()必然的にページ整列され、マッピングは で拡張できますmremap()

于 2011-02-21T02:15:31.467 に答える
1
  1. 通常より厳密なアラインメントで malloc リターン メモリを要求する方法を知りません。Linux での「通常」については、man posix_memalign から (必要に応じて、malloc() の代わりに使用して、より厳密に整列されたメモリを取得できます):

    GNU libc malloc() は常に 8 バイト アラインされたメモリ アドレスを返すため、これらのルーチンは、より大きなアラインメント値が必要な場合にのみ必要です。

  2. malloc()、posix_memalign()、または realloc() によって返される同じポインターを使用して、メモリを解放する必要があります。

  3. 通常どおり realloc() を使用し、十分な余分なスペースを含めて、まだ整列されていない新しいアドレスが返された場合は、少し memmove() して整列させることができます。厄介ですが、私が考えることができる最高のものです。

于 2011-02-21T01:25:41.910 に答える
1

オブジェクトを処理する独自のスラブ アロケータを記述し、 を使用して一度にページを割り当てmmap、最近解放されたアドレスのキャッシュを維持して高速割り当てを行い、すべてのアライメントを処理し、オブジェクトを移動/成長させる柔軟性を提供できます。必要に応じて正確に。malloc汎用的な割り当てには非常に適していますが、データ レイアウトと割り当てのニーズがわかっている場合は、それらの要件を正確に満たすようにシステムを設計できます。

于 2011-02-21T01:50:24.233 に答える
0
  1. システムで実験してください。多くのシステム (特に 64 ビットのシステム) では、malloc()とにかく 16 バイトにアラインされたメモリを取得します。そうでない場合は、余分なスペースを割り当ててポインターを移動する必要があります (ほとんどすべてのマシンで最大 8 バイト)。

    たとえば、x86/64 上の 64 ビット Linux には 16-bytelong doubleがあり、これは 16 バイトでアラインされているため、いずれにせよすべてのメモリ割り当ては 16 バイトでアラインされています。ただし、32 ビット プログラムでsizeof(long double)は は 8 であり、メモリ割り当ては 8 バイト アラインのみです。

  2. free()はい -によって返されるポインターのみを使用できますmalloc()。それ以外は災害のレシピです。

  3. システムが 16 バイト境界整列の割り当てを行う場合、問題はありません。そうでない場合は、独自のリアロケータが必要になります。これは、16 バイトにアラインされた割り当てを行ってからデータをコピーするか、システムを使用して、realloc()必要に応じて再アラインされたデータを調整します。

のマニュアルページを再確認してくださいmalloc()。必要に応じて動作するように微調整するオプションとメカニズムがある場合があります。

MacOS X にはposix_memalign()andがありvalloc()(ページ境界で割り当てられます)、および で識別される一連の「ゾーン化された malloc」関数全体がman malloc_zoned_mallocあり、ヘッダーは<malloc/malloc.h>です。

于 2011-02-21T01:24:52.973 に答える
-1

ジミーできるかもしれません( Microsoft VC++ およびおそらく他のコンパイラで):

#pragma pack(16)

malloc( ) が強制的に 16 バイトでアラインされたポインターを返すようにします。次のようなもの:

ptr_16byte = malloc( 10 * sizeof( my_16byte_aligned_struct ));

malloc( ) でまったく機能する場合は、realloc( ) でも同様に機能すると思います。

ちょっとした考え。

-- ピート

于 2011-02-21T01:46:26.033 に答える