58

私はどのような機能memalign()と機能を理解しようとしposix_memalign()ています。利用可能なドキュメントを読んでも役に立ちませんでした。

誰かがそれがどのように機能し、何のために使用されるかを理解するのを手伝ってくれますか? または、おそらく使用例を提供してください。

Linux メモリの仕組みを理解しようとしています。独自の単純なメモリ プール (断片化の少ないヒープ) を作成する必要があります。

4

6 に答える 6

74

Whereas malloc gives you a chunk of memory that could have any alignment (the only requirement is that it must be aligned for the largest primitive type that the implementation supports), posix_memalign gives you a chunk of memory that is guaranteed to have the requested alignment.

So the result of e.g. posix_memalign(&p, 32, 128) will be a 128-byte chunk of memory whose start address is guaranteed to be a multiple of 32.

This is useful for various low-level operations (such as using SSE instructions, or DMA), that require memory that obeys a particular alignment.

于 2011-07-03T13:25:38.297 に答える
14

mallocプリミティブ型のいずれかで必要な最大アラインメントに設定されたメモリを常に返します。これにより、mallocメモリに必要なタイプを格納できます。の説明についての私の理解は、posix_memalignアドレスがアラインメントとして指定したものの倍数になるメモリ位置を返すということです。

カスタム メモリ プールを作成するときにこれがどれほど役立つかはわかりませんが、これを実装する方法の例を提供してみました。違いは私の例との違いです.で割り当てられたものはすべてmalloc_alignedで解放されなければなりませんfree_aligned; しかし、posix_memalignあなたは使用することができますfree

#include <stdlib.h>
#include <stdio.h>

void *malloc_aligned(size_t alignment, size_t bytes)
{
    // we need to allocate enough storage for the requested bytes, some 
    // book-keeping (to store the location returned by malloc) and some extra
    // padding to allow us to find an aligned byte.  im not entirely sure if 
    // 2 * alignment is enough here, its just a guess.
    const size_t total_size = bytes + (2 * alignment) + sizeof(size_t);

    // use malloc to allocate the memory.
    char *data = malloc(sizeof(char) * total_size);

    if (data)
    {
        // store the original start of the malloc'd data.
        const void * const data_start = data;

        // dedicate enough space to the book-keeping.
        data += sizeof(size_t);

        // find a memory location with correct alignment.  the alignment minus 
        // the remainder of this mod operation is how many bytes forward we need 
        // to move to find an aligned byte.
        const size_t offset = alignment - (((size_t)data) % alignment);

        // set data to the aligned memory.
        data += offset;

        // write the book-keeping.
        size_t *book_keeping = (size_t*)(data - sizeof(size_t));
        *book_keeping = (size_t)data_start;
    }

    return data;
}

void free_aligned(void *raw_data)
{
    if (raw_data)
    {
        char *data = raw_data;

        // we have to assume this memory was allocated with malloc_aligned.  
        // this means the sizeof(size_t) bytes before data are the book-keeping 
        // which points to the location we need to pass to free.
        data -= sizeof(size_t);

        // set data to the location stored in book-keeping.
        data = (char*)(*((size_t*)data));

        // free the memory.
        free(data);
    }
}

int main()
{
    char *ptr = malloc_aligned(7, 100);

    printf("is 5 byte aligned = %s\n", (((size_t)ptr) % 5) ? "no" : "yes");
    printf("is 7 byte aligned = %s\n", (((size_t)ptr) % 7) ? "no" : "yes");

    free_aligned(ptr);

    return 0;
}
于 2011-07-03T16:16:15.257 に答える
13

Oli の回答に加えて、さらに重要な問題を指摘したいと思います。

最近の x86 アーキテクチャでは、メモリからキャッシュにフェッチできる最小量のデータであるキャッシュ ラインは 64 バイトです。構造体のサイズが 56 バイトで、それらの大きな配列があるとします。1 つの要素をルックアップする場合、CPU は 2 つのメモリ要求を発行する必要があります (キャッシュラインの途中であっても、2 つの要求を発行する場合があります)。メモリを待つ必要があり、より多くのキャッシュを使用するため、パフォーマンスが低下し、最終的にキャッシュミス率が高くなります。この場合、単に posix_memalign を使用するだけでは十分ではありませんが、64 バイト境界になるように構造をパディングまたは圧縮する必要があります。

40バイトの構造体を持つことはただの不運です:)

于 2012-06-26T02:49:35.597 に答える
4

How does it work is implementation dependent. The purpose of the function is to give you an n-bytes aligned memory block (the start address of the block is a multiply of n).

于 2011-07-03T13:26:28.227 に答える
3

memalign は廃止されたため (参照: man ページ)、malloc() と posix_memalign() の違いのみをここで説明します。malloc() は 8 バイトにアラインされています (たとえば、RHEL 32 ビットの場合) が、posix_memalign() の場合、アラインメントはユーザー定義可能です。これの使い方を知るには、mprotect() を使用してメモリ属性を設定するのが良い例でしょう。mprotect() を使用するには、メモリ ポインタが PAGE でアラインされている必要があります。そのため、pagesize をアラインメントとして posix_memalign() を呼び出すと、返されたポインターを mprotect() に簡単に送信して、読み取り/書き込み実行可能属性を設定できます。(たとえば、データをメモリ ポインターにコピーした後、そのデータを読み取り専用属性に設定して、変更されないようにすることができます)。"malloc()" の返されたポインターは、ここでは使用できません。

于 2015-01-02T14:03:46.243 に答える