OpenCV原始碼之記憶體分配 指標對齊

2021-07-05 06:14:09 字數 2589 閱讀 7414

原文:

首先,為什麼要指標對齊(pointer alignment)?

指標對齊有時候非常重要,因為許多硬體相關的東西在對齊上存在限制。在有些系統中,某種資料型別只能儲存在偶數邊界的位址處。

例如,在經典的 sparc架構(以及經典的arm)上,你不能從奇數字址讀取乙個超過1位元組的整型資料。嘗試這麼做將會立即終止程式,並伴隨著匯流排錯誤。而在x86架構上,cpu硬體處理了這個問題,只是這麼做將會花費更多時間;通常risc架構是不會為你做這些。舉例如下:

[cpp]view plain

copy

print

?char

c;  

char

*pc = &c;  

int*pi;  

pi = (int

*)pc;  

你可能會發現,*pi的引用將會導致錯誤,因為pc沒有指向乙個以"int"型邊界對齊的資料項。

opencv2.0以上版本很多指標都是被對齊過的,使指標位址能夠被16整除。opencv中的記憶體一般是通過malloc分配,不能保證申請的首位址都是都能被16整除;所以opencv中需要申請的記憶體做一些指標對齊操作。opencv中記憶體分配-指標對齊相關的函式有:

[cpp]view plain

copy

print

?void

* fastmalloc( 

size_t

size )  

void

fastfree(

void

* ptr)  

}  這裡的cv_malloc_align值為16,表示實際儲存資料的首位址是16的倍數;多申請的sizeof(void *)空間用來儲存malloc返回的記憶體首位址,以便在fastfree()中可以正確釋放。假設要申請的有效記憶體大小為x位元組,即size = x;

我的系統是32位,因此sizeof(void *) = 4,下面以**的方式講解以上記憶體申請過程:

這裡ptr = (uchar **)udata + 1;即是alignptr()函式中的第乙個引數,alignptr()函式定義為:

[cpp]view plain

copy

print

?template

<

typename

_tp> 

static

inline

_tp* alignptr(_tp* ptr, 

intn=(

int)

sizeof

(_tp))    

該函式是用來將ptr指向的位址對齊到n邊界,使得到的位址是n的倍數,在這裡n = cv_mallocd_align = 16;

ptr = 0xyy yy yy yy,那麼ptr +n - 1計算如下:

0xyy yy yy yy

+                     0f

-------------------------------

當ptr的低4位不全為0時,ptr + n - 1的結果中第5位將會進一。

然後再與(-n)相與,-n == 0xf0,所以最終返回的位址形式為0xyy yy yy y0,即為cv_mallocd_align = 16的倍數。

例如,(size_t)ptr == 0或16或32 ... ...,即16的整數倍,那麼返回的位址就是本身;但如果(size_t)ptr == 2,則返回的位址就是16,如果是18,則返回的位址就是32。

下面以**的形式分別舉例說明,以上分配過程。

當(size_t)ptr % cv_mallocd_align == 15時,

那麼對齊後的位址adata相對於ptr有乙個偏移量,偏移量為1;然後adata[-1] = udata,就是將malloc返回的首位址給存起來,這段空間也就是malloc時多申請的sizeof(void *)大小的空間。

當(size_t)ptr % cv_mallocd_align == 1時,

那麼對齊後的位址adata相對於ptr有乙個偏移量,偏移量為15;

fastmalloc返回的位址是adata,而由adata是很容易求出malloc返回的udata,因此fastfree(adata)中就是這樣由adata求出udata,從而順利釋放記憶體。

採用fastmalloc()申請的記憶體有效利用率為

所以申請的記憶體塊越大,其有效利用率就越大。

另外,其實在gnu系統中,由malloc或realloc返回的記憶體塊的位址總是8的倍數(或者在64位系統上16倍);如果你需要一記憶體塊,其位址是2的更高次冪的倍數,那麼可以用stdlib.h.檔案中宣告的aligned_allocposix_memalign

STL原始碼分析之記憶體池

前言上一節只分析了第二級配置器是由多個鍊錶來存放相同記憶體大小,當沒有空間的時候就向記憶體池索取就行了,卻沒有具體分析記憶體池是怎麼儲存空間的,是不是記憶體池真的有用不完的記憶體,本節我們就具體來分析一下 記憶體池static data template的初始化 template char defa...

C 之記憶體分配

很多人都覺得學習 c 是特別困難的事情。c 學習是比較複雜的 它的記憶體分配 指標 以及物件導向思想的實現等等,確實需要一定的技術積累。我們將以專題的形式,為大家逐一剖析 c 的技術重點和難點。本專題討論的就是記憶體分配。學習 c 如果不了解記憶體分配是一件非常可悲的事情。而且,可以這樣講,乙個 c...

C之記憶體分配

常見記憶體分配的錯誤 記憶體分配方式 1.靜態儲存區域 內存在程式編譯的時候就分配好,這塊內存在程式的整個執行期間都存在,如全域性變數 static變數 2.棧 在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時,這些儲存單元會被自動釋放。效率高,但分配的記憶體容量比較有限。3...