在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

相關文章
相關標籤/搜索