关于memalign和malloc的区别
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于memalign和malloc的区别相关的知识,希望对你有一定的参考价值。
参考技术A 在GNU系统中,malloc或realloc返回的内存块地址都是8的倍数(如果是64位系统,则为16的倍数)。如果你需要更大的粒度,请使用memalign或valloc。这些函数在头文件“stdlib.h”中声明。在GNU库中,可以使用函数free释放memalign和valloc返回的内存块。但无法在BSD系统中使用,而且BSD系统中并未提供释放这样的内存块的途径。
函数:void * memalign (size_t boundary, size_t size)
函数memalign将分配一个由size指定大小,地址是boundary的倍数的内存块。参数boundary必须是2的幂!函数memalign可以分配较大的内存块,并且可以为返回的地址指定粒度。
函数:void * valloc (size_t size)
使用函数valloc与使用函数memalign类似,函数valloc的内部实现里,使用页的大小作为对齐长度,使用memalign来分配内存。它的实现如下所示:
void *
valloc (size_t size)
return memalign (getpagesize (), size);
本回答被提问者和网友采纳
posix_memalign 有对应的 c++ 吗?
【中文标题】posix_memalign 有对应的 c++ 吗?【英文标题】:Is there a c++ counterpart to posix_memalign? 【发布时间】:2014-12-17 01:09:56 【问题描述】:当我在 C++ 代码中调用 posix_memalign
为 Foo
类型的对象分配对齐内存时,我需要对该指向 void**
的指针的地址执行 reinterpret_cast
。
一般来说,当我遇到这种情况时,这意味着我缺少一些语言功能。也就是说,当我应该调用new
时,感觉就像我在c++
中调用malloc
。
,
c++
中的对齐内存分配是否存在类型感知 new
等效项?
【问题讨论】:
我认为它会默认对齐(使用 new 时),除非您有目的地确保它不是? @Borgleader,我也这么认为,但事实并非如此。我在运行时检查了地址的最后 6 位上的assert
,但失败了。
使用alignas
关键字?
为Foo
重载新的以使用posix_memalign
?
您的 GCC 版本可能支持对齐扩展,其工作方式类似于现在标准化的对齐。见gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html。
【参考方案1】:
我将首先从核心建议开始。
Foo* aligned_foo()
void* raw = 0;
if(posix_memalign(&raw, 8, sizeof(Foo)))
return 0; // we could throw or somehow communicate the failure instead
try
return new(raw) Foo();
catch(...)
free(raw);
throw;
然后当你完成Foo* foo
后,使用foo->~Foo(); free(foo);
而不是delete
。
请注意缺少reinterpret_cast
s。
这是一个使其通用的尝试:
// note: stateless. Deleting a derived with a base without virtual ~base a bad idea:
template<class T>
struct free_then_delete
void operator()(T*t)const
if(!t)return;
t->~T();
free(t);
;
;
template<class T>
using aligned_ptr=std::unique_ptr<T,free_then_delete<T>>;
// the raw version. Dangerous, because the `T*` requires special deletion:
template<class T,class...Args>
T* make_aligned_raw_ptr(size_t alignment, Args&&...args)
void* raw = 0;
if(int err = posix_memalign(&raw, alignment, sizeof(T)))
if (err==ENOMEM)
throw std::bad_alloc;
return 0; // other possibility is bad alignment: not an exception, just an error
try
// returns a T*
return new(raw) T(std::forward<Args>(args)...);
catch(...) // the constructor threw, so clean up the memory:
free(raw);
throw;
template<class T,class...Args> // ,class... Args optional
aligned_ptr<T> make_aligned_ptr(size_t alignment=8, Args&&...args)
T* t = make_aligned_raw_ptr<T>(alignment, std::forward<Args>(args)...);
if (t)
return aligned_ptr<T>(t);
else
return nullptr;
unique_ptr
别名 aligned_ptr
将销毁器与指针捆绑在一起——因为这些数据需要销毁和释放,而不是删除,这很清楚。您仍然可以.release()
指针移出,但您仍然需要执行这些步骤。
【讨论】:
@dyp 失败(非零返回值)我们中止并返回一个仍然为空的retval
@dyp 已修复。添加了alignment
参数。我可以让错误代码抛出,但是......我很懒。我想抛出内存是有道理的。 ......那会奏效:aligned_ptr<T>
不能投入建设这一事实也让人感到温暖和模糊。我试图启用 NRVO,所以所有路径都返回 retval
。 OP 表明他们正在使用一些古老的编译器,因此“好吧,你不必这样做”,return ;
在 C++03 中不太漂亮。
不确定你在哪里return ;
。对于第一个返回 return nullptr;
将起作用,因为该 ctor 不明确。第二个返回不能使用
,因为那个ctor 是显式的。
@dyp 我修复了另一个错误,并颠倒了建议——把具体的(简短的)版本放在第一位,用你的return new(raw) Foo();
那个很干净,我几乎想用它作为核心unique_ptr
一个 -- 让unique_ptr
一个只需用删除器包装即可。
@dyp 重写。我认为_raw_ptr
和_ptr
版本更简洁。现在抛出内存不足,如new
。【参考方案2】:
实际上,您不想执行reinterpret_cast
,因为您的Foo
构造函数不会被调用。如果需要从特殊位置分配内存,则调用placement new 在该内存中构造对象:
void* alloc;
posix_memalign(&alloc, 8, sizeof(Foo));
Foo* foo = new (foo) Foo();
唯一的其他方法(C++11 之前)是为您的类覆盖 new
运算符。如果您有一个总是需要这种特殊分配的特定类,则此方法有效:
class Foo
void* operator new(size_t size)
void* newobj;
posix_memalign(&newobj, 8, sizeof(Foo));
return newobj;
;
然后,无论何时您调用new Foo()
,它都会调用此分配器。请参阅http://en.cppreference.com/w/cpp/memory/new/operator_new 了解更多信息。可以为单个类或全局覆盖 operator new
和 operator delete
。
【讨论】:
如果我不执行reinterpret_cast
,我会收到编译器错误(或者可能是升级警告)。
另外我一点也不介意没有调用构造函数(我已经做了一个新的放置),但我非常关心对齐。
对不起,我正在考虑重新解释演员在另一个方向(对 Foo)。确实,Foo** 需要演员表作废**。
我认为这个reinterpret_cast
违反了严格的别名规则。你可以试着通过这样写来避免这种情况:void* foo_v; posix_memalign(&foo_v, 8, sizeof(Foo)); auto foo = new (foo_v) Foo();
如果你说std::vector<Foo>
,你会大吃一惊:-S【参考方案3】:
C++11 增加了对对齐声明和对齐分配的原生语言支持。
您可以在 C++11 中的类型上指定 alignas(N)
,以指定新对象的最小对齐方式,默认 new
将遵守该对齐方式。
来自cppreference的示例:
struct alignas(16) sse_t // SSE-safe struct aligned on 16-byte boundaries
float v[4];
;
那么你可以简单地做
sse_t *ssevec = new sse_t;
要替换posix_memalign
,您可以使用std::aligned_storage<sizeof(T), N>
,同样在C++11 中。
【讨论】:
AFAIK,alignas 说明符仅适用于变量声明(静态/全局和本地/堆栈变量)。您可以在声明站点将其指定为声明类型的限定符,也可以在我们用于声明的类之一上指定。 这个答案部分错误!在 C++11 中,new
在某些情况下不尊重 alignas()
: ***.com/questions/15511909/…以上是关于关于memalign和malloc的区别的主要内容,如果未能解决你的问题,请参考以下文章
posix_memalign、malloc 和 calloc 与 lli 解释器有问题
关于 malloc 和 new 在各自处理内存分配的机制方面的区别? [复制]
我们啥时候需要使用 posix_memalign 而不是 malloc?