在C++中实现aligned_malloc

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,须要配合使用,不然会有内存泄漏问题。code

#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;
}

添加一个测试程序,blog

#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为边界,而且分配的内存最后也被成功释放了,函数是正确的。it

源代码说明

本小段主要向不大了解解决思路的小伙伴作一些简单解释,程序大佬能够一笑而过哈。io

首先咱们要明确咱们的解决方案,既然malloc分配的指针地址不能达到咱们想要的字节对齐效果,咱们就本身来调整这个指针。因此咱们的作法是ast

  • 比用户实际须要的多分配一些内存,多分配的部分等于对齐大小减一再加上指针大小。加上对齐大小减一很好理解,是为了以后的对齐作准备,而加上指针大小是为了以后有空间保存原始指针,对应分配函数中的前2行
  • 在malloc返回的原始指针的基础上,加上指针大小,再对齐(采用的方法就是加上对齐大小减1再作位运算),这个运算结果就是咱们想要的对齐后的指针,也是咱们返回给用户的指针,对应分配函数中的3~5行
  • 咱们还须要保存malloc返回的原始指针,不然free的时候会出问题。这时咱们以前多分配的一个指针大小就有用武之地了,保存原始指针在那个地址,分配函数的最后几行就在作这个事
  • 当free的时候,咱们知道原始指针存放在咱们使用的指针的前一个指针大小偏移的内存里面,经过一些运算取得这个内存地址,再根据里面存放的原始指针调用free完成内存释放

这就是在C++中手动实现aligned_malloc的方法,但愿你们在使用较老版本的C++的时候,有须要能够用上。若是使用的版本是C++17以上,那么仍是推荐使用系统自带的方法。class

相关文章
相关标签/搜索