首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >整页Malloc

整页Malloc
EN

Stack Overflow用户
提问于 2013-02-21 23:45:15
回答 5查看 6.1K关注 0票数 5

我正在尝试通过一次使用整个页面来优化我的程序的内存分配。

我像这样抓取页面大小:sysconf(_SC_PAGESIZE);,然后计算适合页面的元素总数:elements=pageSize/sizeof(Node);

我在想,当我真的去malloc我的内存时,我会使用malloc(elements*sizeof(Node));似乎sifeof(节点)的乘法和除法会被抵消,但对于整数除法,我不相信是这样的。

这是一次使用malloc整个页面的最好方法吗?

谢谢

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-02-22 00:37:47

malloc函数没有任何页面大小的概念。除非您分配的页面也与页面边界对齐,否则您无法从以这种方式调用malloc中获得任何好处。只要malloc你需要的元素就行了,不要担心微优化几乎肯定不会给你带来任何好处。

是的,Linux内核一直在做这样的事情。这有两个原因:

  1. 您不希望分配大于一个页面的块,因为这会显著增加分配失败的风险。
  2. 内核分配是以页为单位进行的,而不是像C库那样一次性分配大量内存,然后将其拆分成小组件。

如果您确实想分配页面大小的内存量,那么使用sysconf(_SC_PAGESIZE)的结果作为您的大小参数。但几乎可以肯定的是,您的分配会跨越两个页面。

票数 6
EN

Stack Overflow用户

发布于 2013-02-22 01:01:13

计算elements=pageSize/sizeof(Node);不会考虑添加到malloc()返回的任何内存块/块的malloc()元数据。在许多情况下,malloc()将返回一个可能至少与min(sizeof(double),2 * sizeof(void *))边界对齐的内存块(顺便说一句,32字节正变得非常普遍...)。如果malloc()让一个内存块在页面上对齐,添加它的块(使用填充),并且您写入了整个页面大小的数据,那么最后一个字节就离开了第一个页面:所以您最终使用了2个页面。

想要一个完整的页面,只为你自己,不担心浪费内存,不像评论中建议的那样使用mmap() / VirtualAlloc()?您的位置如下:

代码语言:javascript
复制
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的缓存行大小的倍数,也没有检查过如何改善缓存局部性,也没有找到减少内存碎片的方法。所以你可能走错了路:让它先工作,配置文件,优化你的算法,配置文件,微优化在最后一个选项。

票数 5
EN

Stack Overflow用户

发布于 2018-03-22 00:35:16

C11标准添加了aligned_alloc调用,因此您可以执行以下操作:

代码语言:javascript
复制
#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的内存开销,并假设它总是恒定的,那么要求更少的内存开销通常会给我们带来我们想要的吗?

代码语言:javascript
复制
#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 )来避免此问题。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15006372

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档