C11標準ではaligned_alloc呼び出しが追加されたため、次のようなことができます。
#include <stdlib.h>
#include <unistd.h>
void *alloc_page( void )
{
long page_size = sysconf( _SC_PAGESIZE ); /* arguably could be a constant, #define, etc. */
return ( page_size > 0 ? aligned_alloc( page_size, page_size ) : NULL );
}
他の人が指摘しているように、このアプローチの問題は、通常、標準のalloc呼び出しの実装により、割り当てられたメモリの直前に格納される簿記のオーバーヘッドが追加されることです。したがって、この割り当ては通常、2つのページにまたがります。使用するために返されたページと、アロケータの簿記で使用される別のページの最後です。
つまり、このメモリを解放または再割り当てするときに、1ページだけでなく2ページに触れる必要がある場合があります。また、この方法でメモリのすべてまたはほとんどを割り当てると、OSレベルでプロセスに割り当てられたページの約半分がアロケータの簿記に使用されるのはごくわずかであるため、大量の仮想メモリを「浪費」する可能性があります。 。
これらの問題がどれほど重要であるかを一般的に言うのは難しいですが、どうにかして回避することが望ましいでしょう。残念ながら、私はまだそれを行うためのクリーンで簡単でポータブルな方法を見つけていません。
==============================
補遺:mallocのメモリオーバーヘッドを動的に把握し、それが常に一定であると仮定できる場合、それを求めることは通常、私たちが望むものを私たちに与えることはありませんか?
#include <stdlib.h>
#include <unistd.h>
/* decent default guesses (e.g. - Linux x64) */
static size_t Page_Size = 4096;
static size_t Malloc_Overhead = 32;
/* call once at beginning of program (i.e. - single thread, no allocs yet) */
int alloc_page_init( void )
{
int ret = -1;
long page_size = sysconf( _SC_PAGESIZE );
char *p1 = malloc( 1 );
char *p2 = malloc( 1 );
size_t malloc_overhead;
if ( page_size <= 0 || p1 == NULL || p2 == NULL )
goto FAIL;
malloc_overhead = ( size_t ) ( p2 > p1 ? p2 - p1 : p1 - p2 ); /* non-standard pointer math */
if ( malloc_overhead > 64 || malloc_overhead >= page_size )
goto FAIL;
Page_Size = page_size;
Malloc_Overhead = malloc_overhead;
ret = 0;
FAIL:
if ( p1 )
free( p1 );
if ( p2 )
free( p2 );
return ret;
}
void *alloc_page( void )
{
return aligned_alloc( Page_Size - Malloc_Overhead, Page_Size - Malloc_Overhead );
}
回答:おそらくそうではありません。たとえば、「「実装によってサポートされる」要件の例として、POSIX関数posix_memalignは、2の累乗とsizeof(void *)の倍数であり、POSIXベースのアライメントを受け入れるためです。 align_allocの実装は、これらの要件を継承します。」
上記のコードは、2の累乗であるアライメントを要求しない可能性が高いため、ほとんどのプラットフォームで失敗する可能性があります。
これは、標準の割り当て関数の一般的な実装では避けられない問題のようです。したがって、ページサイズに基づいて調整して割り当て、別のページにあるアロケータの簿記のペナルティを支払うか、mmapなどのOS固有の呼び出しを使用してこの問題を回避するのがおそらく最善です。