内存对齐指令详解(posix_memalign)
目錄
posix_memalign
opencv中的內(nèi)存對(duì)齊函數(shù)源碼
posix_memalign
預(yù)對(duì)齊內(nèi)存的分配
在大多數(shù)情況下,編譯器和C庫(kù)透明地幫你處理對(duì)齊問(wèn)題。POSIX 標(biāo)明了通過(guò)malloc( ),?calloc( ), 和?realloc( )?返回的地址對(duì)于任何的C類(lèi)型來(lái)說(shuō)都是對(duì)齊的。在Linux中,這些函數(shù)返回的地址在32位系統(tǒng)是以8字節(jié)為邊界對(duì)齊,在64位系統(tǒng)是以16字節(jié)為邊界對(duì)齊的。有時(shí)候,對(duì)于更大的邊界,例如頁(yè)面,程序員需要?jiǎng)討B(tài)的對(duì)齊。雖然動(dòng)機(jī)是多種多樣的,但最常見(jiàn)的是直接塊I/O的緩存的對(duì)齊或者其它的軟件對(duì)硬件的交互,因此,POSIX 1003.1d提供一個(gè)叫做posix_memalign( )的函數(shù):
/* one or the other -- either suffices */ #define _XOPEN_SOURCE 600 #define _GNU_SOURCE #include <stdlib.h> int posix_memalign (void **memptr,size_t alignment,size_t size);* See http://perens.com/FreeSoftware/ElectricFence/ and http://valgrind.org, respectively. 調(diào)用posix_memalign( )成功時(shí)會(huì)返回size字節(jié)的動(dòng)態(tài)內(nèi)存,并且這塊內(nèi)存的地址是alignment的倍數(shù)。參數(shù)alignment必須是2的冪,還是void指針的大小的倍數(shù)。返回的內(nèi)存塊的地址放在了memptr里面,函數(shù)返回值是0.調(diào)用失敗時(shí),沒(méi)有內(nèi)存會(huì)被分配,memptr的值沒(méi)有被定義,返回如下錯(cuò)誤碼之一: EINVAL 參數(shù)不是2的冪,或者不是void指針的倍數(shù)。 ENOMEM 沒(méi)有足夠的內(nèi)存去滿(mǎn)足函數(shù)的請(qǐng)求。 要注意的是,對(duì)于這個(gè)函數(shù),errno不會(huì)被設(shè)置,只能通過(guò)返回值得到。由posix_memalign( )獲得的內(nèi)存通過(guò)free( )釋放。用法很簡(jiǎn)單: char *buf; int ret; /* allocate 1 KB along a 256-byte boundary */ ret = posix_memalign (&buf, 256, 1024); if (ret) {fprintf (stderr, "posix_memalign: %s\n",strerror (ret));return -1; } /* use 'buf'... */ free (buf);與對(duì)齊有關(guān)的問(wèn)題的范圍要超過(guò)標(biāo)準(zhǔn)類(lèi)型的自然對(duì)齊和動(dòng)態(tài)存儲(chǔ)器地分配。例如,非標(biāo)準(zhǔn)和復(fù)雜的類(lèi)型比標(biāo)準(zhǔn)類(lèi)型有更復(fù)雜的要求。另外,對(duì)對(duì)齊的關(guān)注在給指向不同類(lèi)型的指針賦值和使用強(qiáng)轉(zhuǎn)時(shí)顯得加倍的重要。非標(biāo)準(zhǔn)類(lèi)型。非標(biāo)準(zhǔn)和復(fù)雜的數(shù)據(jù)類(lèi)型的對(duì)齊比簡(jiǎn)單的自然對(duì)齊有著更多的要求。這里四個(gè)有很有用的方法: ?一個(gè)結(jié)構(gòu)的對(duì)齊要求是和它的成員中最大的那個(gè)類(lèi)型一樣的。例如,一個(gè)結(jié)構(gòu)中最大的是以4字節(jié)對(duì)齊的32bit的整形,那么這個(gè)結(jié)構(gòu)至少以4字節(jié)對(duì)齊。 ?結(jié)構(gòu)也引入了填充的需要,用來(lái)保證每一個(gè)成員都符合自己的對(duì)齊要求。所以,如果一個(gè)char (可能以1字節(jié)對(duì)齊)后跟著一個(gè)int (可能以4字節(jié)對(duì)齊),編譯器會(huì)自動(dòng)地插入3個(gè)字節(jié)作為填充來(lái)保證int以4字節(jié)對(duì)齊。 程序員有時(shí)候排列結(jié)構(gòu)里面的成員-例如,以大小來(lái)遞減-來(lái)是使用作填充的垃圾空間最少。GCC的選項(xiàng)- Wpadded能對(duì)這些努力有幫助,因?yàn)樗沟迷诰幾g器偷偷插入填充時(shí)產(chǎn)生警告。 ?一個(gè)聯(lián)合的對(duì)齊和聯(lián)合里最大的類(lèi)型一樣。 ?一個(gè)數(shù)組的對(duì)齊和數(shù)組里的元素一樣。所以,數(shù)組的對(duì)齊并不比單單的一個(gè)成員嚴(yán)格,這樣能使數(shù)組里面的所有成員都是自然對(duì)齊的。其他平臺(tái)的內(nèi)存對(duì)齊函數(shù)雷同:如win32系統(tǒng)函數(shù):_aligned_malloc(size,?alignment),android系統(tǒng)函數(shù):memalign(alignment,?size)
opencv中的內(nèi)存對(duì)齊函數(shù)源碼(ncnn寫(xiě)法也一樣,應(yīng)該是參考o(jì)pencv)
template<typename _Tp> static inline _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) {assert((n & (n - 1)) == 0); // n is a power of 2return (_Tp*)(((size_t)ptr + n - 1) & -n); }void* fastMalloc(size_t size) {unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN);if (udata){unsigned char** adata = alignPtr((unsigned char**)udata + 1, CV_MALLOC_ALIGN);/*保存原始的內(nèi)存地址,adata是對(duì)齊后的地址,若直接釋放這個(gè)地址,則會(huì)產(chǎn)生內(nèi)存泄露。malloc得到的指針地址保存在adata的前一塊區(qū)域內(nèi)*/adata[-1] = udata;return adata;}return NULL; }void fastFree(void* ptr) {if (ptr){unsigned char* udata = ((unsigned char**)ptr)[-1];assert(udata < (unsigned char*)ptr &&((unsigned char*)ptr - udata) <= (std::ptrdiff_t)(sizeof(void*) + CV_MALLOC_ALIGN));free(udata);} }CV_MALLOC_ALIGN為需要對(duì)齊的bit數(shù)?
?
總結(jié)
以上是生活随笔為你收集整理的内存对齐指令详解(posix_memalign)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 代码执行流水之循环展开优化
- 下一篇: 岛屿数量—leetcode200