在C++中實(shí)現(xiàn)aligned_malloc的方法
malloc的默認(rèn)行為
大家都知道C++中可以直接調(diào)用malloc請(qǐng)求內(nèi)存被返回分配成功的內(nèi)存指針,該指針指向的地址就是分配得到的內(nèi)存的起始地址。比如下面的代碼
int main() { void *p = malloc(1024); printf("0x%p\n", p); free(p); }
請(qǐng)求了一個(gè)大小為1024的內(nèi)存塊并打印出來,一切都很完美。
我們看看這塊內(nèi)存的地址。
可以看到,在64bit機(jī)器上,malloc默認(rèn)行為會(huì)將分配的地址以16-byte對(duì)齊,如果我們想改變這種默認(rèn)行為,提供32-byte或者64-byte對(duì)齊,應(yīng)該怎么做呢?
實(shí)現(xiàn)aligned_malloc
源代碼
從C++17開始,可以使用aligned_alloc函數(shù)達(dá)到這個(gè)目的,但是如果使用較老的C++版本,如C++14,C++11,我們需要手動(dòng)寫一個(gè)實(shí)現(xiàn)。
話不多說,先貼代碼如下,aligned_malloc和aligned_free,需要配合使用,否則會(huì)有內(nèi)存泄漏問題。
#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; }
添加一個(gè)測(cè)試程序,
#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; }
看看結(jié)果,
分配的內(nèi)存地址都是以64-byte為邊界,并且分配的內(nèi)存最后也被成功釋放了,函數(shù)是正確的。
源代碼說明
本小段主要向不大了解解決思路的小伙伴做一些簡單解釋,程序大佬可以一笑而過哈。
首先我們要明確我們的解決方案,既然malloc分配的指針地址不能達(dá)到我們想要的字節(jié)對(duì)齊效果,我們就自己來調(diào)整這個(gè)指針。所以我們的做法是
- 比用戶實(shí)際需要的多分配一些內(nèi)存,多分配的部分等于對(duì)齊大小減一再加上指針大小。加上對(duì)齊大小減一很好理解,是為了之后的對(duì)齊做準(zhǔn)備,而加上指針大小是為了之后有空間保存原始指針,對(duì)應(yīng)分配函數(shù)中的前2行
- 在malloc返回的原始指針的基礎(chǔ)上,加上指針大小,再對(duì)齊(采用的方法就是加上對(duì)齊大小減1再做位運(yùn)算),這個(gè)運(yùn)算結(jié)果就是我們想要的對(duì)齊后的指針,也是我們返回給用戶的指針,對(duì)應(yīng)分配函數(shù)中的3~5行
- 我們還需要保存malloc返回的原始指針,否則free的時(shí)候會(huì)出問題。這時(shí)我們之前多分配的一個(gè)指針大小就有用武之地了,保存原始指針在那個(gè)地址,分配函數(shù)的最后幾行就在做這個(gè)事
- 當(dāng)free的時(shí)候,我們知道原始指針存放在我們使用的指針的前一個(gè)指針大小偏移的內(nèi)存里面,通過一些運(yùn)算取得這個(gè)內(nèi)存地址,再根據(jù)里面存放的原始指針調(diào)用free完成內(nèi)存釋放
這就是在C++中手動(dòng)實(shí)現(xiàn)aligned_malloc的方法,希望大家在使用較老版本的C++的時(shí)候,有需要可以用上。如果使用的版本是C++17以上,那么還是推薦使用系統(tǒng)自帶的方法。
到此這篇關(guān)于在C++中實(shí)現(xiàn)aligned_malloc的文章就介紹到這了,更多相關(guān)C++實(shí)現(xiàn)aligned_malloc內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用C++如何實(shí)現(xiàn)一個(gè)阻塞隊(duì)列詳解
這篇文章主要給大家介紹了關(guān)于利用C++如何實(shí)現(xiàn)一個(gè)阻塞隊(duì)列的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10C語言當(dāng)函數(shù)執(zhí)行成功時(shí)return1還是0
本文主要介紹了C語言當(dāng)函數(shù)執(zhí)行成功時(shí)return1還是0,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09C++?OpenCV實(shí)現(xiàn)物體尺寸測(cè)量示例詳解
本文主要介紹了利用OpenCV對(duì)物體的尺寸進(jìn)行測(cè)量,即先定位到待測(cè)物體的位置,然后測(cè)量物體的寬高。感興趣的同學(xué)可以跟隨小編一起學(xué)習(xí)學(xué)習(xí)2022-01-01Qt?多語言程序設(shè)計(jì)的實(shí)現(xiàn)
本文主要介紹了Qt?多語言程序設(shè)計(jì)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01C++中默認(rèn)無參構(gòu)造函數(shù)的工作機(jī)制淺析
構(gòu)造函數(shù)主要作用在于創(chuàng)建對(duì)象時(shí)為對(duì)象的成員屬性賦值,構(gòu)造函數(shù)由編譯器自動(dòng)調(diào)用,無須手動(dòng)調(diào)用;析構(gòu)函數(shù)主要作用在于對(duì)象銷毀前系統(tǒng)自動(dòng)調(diào)用,執(zhí)行一些清理工作2023-02-02C/C++判斷傳入的UTC時(shí)間是否當(dāng)天的實(shí)現(xiàn)方法
在項(xiàng)目中經(jīng)常會(huì)顯示一個(gè)時(shí)間,如果這個(gè)時(shí)間在今日內(nèi)就顯示為時(shí)分秒,否則顯示為年月日,有需要的朋友可以參考一下2014-01-01