我正在尝试通过一次使用整个页面来优化我的程序的内存分配。
我像这样抓取页面大小:sysconf(_SC_PAGESIZE);,然后计算适合页面的元素总数:elements=pageSize/sizeof(Node);
我在想,当我真的去malloc我的内存时,我会使用malloc(elements*sizeof(Node));似乎sifeof(节点)的乘法和除法会被抵消,但对于整数除法,我不相信是这样的。
这是一次使用malloc整个页面的最好方法吗?
谢谢
发布于 2013-02-22 00:37:47
malloc函数没有任何页面大小的概念。除非您分配的页面也与页面边界对齐,否则您无法从以这种方式调用malloc中获得任何好处。只要malloc你需要的元素就行了,不要担心微优化几乎肯定不会给你带来任何好处。
是的,Linux内核一直在做这样的事情。这有两个原因:
如果您确实想分配页面大小的内存量,那么使用sysconf(_SC_PAGESIZE)的结果作为您的大小参数。但几乎可以肯定的是,您的分配会跨越两个页面。
发布于 2013-02-22 01:01:13
计算elements=pageSize/sizeof(Node);不会考虑添加到malloc()返回的任何内存块/块的malloc()元数据。在许多情况下,malloc()将返回一个可能至少与min(sizeof(double),2 * sizeof(void *))边界对齐的内存块(顺便说一句,32字节正变得非常普遍...)。如果malloc()让一个内存块在页面上对齐,添加它的块(使用填充),并且您写入了整个页面大小的数据,那么最后一个字节就离开了第一个页面:所以您最终使用了2个页面。
想要一个完整的页面,只为你自己,不担心浪费内存,不像评论中建议的那样使用mmap() / VirtualAlloc()?您的位置如下:
int ret;
void *ptr = NULL;
size_t page_size = sysconf(_SC_PAGESIZE);
ret = posix_memalign(&ptr, page_size, page_size);
if (ret != 0 || ptr == NULL) {
fprintf(stderr, "posix_memalign failed: %s\n", strerror(ret));
}顺便说一句,这可能是关于微优化。您可能还没有检查过Node的缓存行大小的倍数,也没有检查过如何改善缓存局部性,也没有找到减少内存碎片的方法。所以你可能走错了路:让它先工作,配置文件,优化你的算法,配置文件,微优化在最后一个选项。
发布于 2018-03-22 00:35:16
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调用的实现会增加一些存储在分配的内存之前的记账开销。因此,这种分配通常会跨越两个页面:供您使用的返回页面,以及分配器记账使用的另一个页面的末尾。
这意味着当您释放或重新分配内存时,它可能需要接触两个页面,而不仅仅是一个页面。此外,如果您以这种方式分配所有或大部分内存,则可能会“浪费”大量虚拟内存,因为在操作系统级别分配给进程的页面中,大约有一半只会被用于分配器的记账。
很难说这些问题有多重要,但最好能以某种方式避免。不幸的是,我还没有想出一种干净、简单和可移植的方法来做到这一点。
==============================
附录:如果你可以动态计算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的aligned_alloc实现继承了这些需求。”
上面的代码可能不会请求2的幂对齐,因此在大多数平台上可能会失败。
在标准分配函数的典型实现中,这似乎是一个不可避免的问题。因此,最好只是根据页面大小进行对齐和分配,并且可能要付出分配器的记账驻留在另一个页面上的代价,或者使用特定于操作系统的调用(如mmap )来避免此问题。
https://stackoverflow.com/questions/15006372
复制相似问题