时间:2022-07-19 10:16:47 | 栏目:C代码 | 点击:次
malloc的默认行为
大家都知道C++中可以直接调用malloc请求内存被返回分配成功的内存指针,该指针指向的地址就是分配得到的内存的起始地址。比如下面的代码
int main() { void *p = malloc(1024); printf("0x%p\n", p); free(p); }
请求了一个大小为1024的内存块并打印出来,一切都很完美。
我们看看这块内存的地址。
可以看到,在64bit机器上,malloc默认行为会将分配的地址以16-byte对齐,如果我们想改变这种默认行为,提供32-byte或者64-byte对齐,应该怎么做呢?
实现aligned_malloc
源代码
从C++17开始,可以使用aligned_alloc函数达到这个目的,但是如果使用较老的C++版本,如C++14,C++11,我们需要手动写一个实现。
话不多说,先贴代码如下,aligned_malloc和aligned_free,需要配合使用,否则会有内存泄漏问题。
#include <memory> void* aligned_malloc(size_t size, size_t alignment) { size_t offset = alignment - 1 + sizeof(void*); void * originalP = malloc(size + offset); size_t originalLocation = reinterpret_cast<size_t>(originalP); size_t realLocation = (originalLocation + offset) & ~(alignment - 1); void * realP = reinterpret_cast<void*>(realLocation); size_t originalPStorage = realLocation - sizeof(void*); *reinterpret_cast<void**>(originalPStorage) = originalP; return realP; } void aligned_free(void* p) { size_t originalPStorage = reinterpret_cast<size_t>(p) - sizeof(void*); free(*reinterpret_cast<void**>(originalPStorage)); } int main() { void * p = aligned_malloc(1024, 64); printf("0x%p\n", p); aligned_free(p); return 0; }
添加一个测试程序,
#include <assert.h> void TestAlignedMalloc() { const int size = 100; const int alignment = 64; void* testArray[size]; for (int i = 0; i < size; ++i) { void * p = aligned_malloc(1024, alignment); assert((reinterpret_cast<size_t>(p) & (alignment - 1)) == 0); printf("0x%p\n", p); testArray[i] = p; } for (int i = 0; i < size; ++i) { aligned_free(testArray[i]); } } int main() { TestAlignedMalloc(); return 0; }
看看结果,
分配的内存地址都是以64-byte为边界,并且分配的内存最后也被成功释放了,函数是正确的。
源代码说明
本小段主要向不大了解解决思路的小伙伴做一些简单解释,程序大佬可以一笑而过哈。
首先我们要明确我们的解决方案,既然malloc分配的指针地址不能达到我们想要的字节对齐效果,我们就自己来调整这个指针。所以我们的做法是
这就是在C++中手动实现aligned_malloc的方法,希望大家在使用较老版本的C++的时候,有需要可以用上。如果使用的版本是C++17以上,那么还是推荐使用系统自带的方法。