FFmpeg原始碼簡單分析:記憶體的分配和釋放(av_malloc()、av_free()等)
=====================================================
FFmpeg的庫函式原始碼分析文章列表:
【架構圖】
【通用】
【解碼】
【編碼】
【其它】
【指令碼】
【H.264】
=====================================================
本文簡單記錄一下FFmpeg中記憶體操作的函式。
記憶體操作的常見函式位於libavutil\mem.c中。本文記錄FFmpeg開發中最常使用的幾個函式:av_malloc(),av_realloc(),av_mallocz(),av_calloc(),av_free(),av_freep()。
av_malloc()
av_malloc()是FFmpeg中最常見的記憶體分配函式。它的定義如下。
#define FF_MEMORY_POISON 0x2a #define ALIGN (HAVE_AVX ? 32 : 16) static size_t max_alloc_size= INT_MAX; void *av_malloc(size_t size) { void *ptr = NULL; #if CONFIG_MEMALIGN_HACK long diff; #endif /* let's disallow possibly ambiguous cases */ if (size > (max_alloc_size - 32)) return NULL; #if CONFIG_MEMALIGN_HACK ptr = malloc(size + ALIGN); if (!ptr) return ptr; diff = ((~(long)ptr)&(ALIGN - 1)) + 1; ptr = (char *)ptr + diff; ((char *)ptr)[-1] = diff; #elif HAVE_POSIX_MEMALIGN if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation if (posix_memalign(&ptr, ALIGN, size)) ptr = NULL; #elif HAVE_ALIGNED_MALLOC ptr = _aligned_malloc(size, ALIGN); #elif HAVE_MEMALIGN #ifndef __DJGPP__ ptr = memalign(ALIGN, size); #else ptr = memalign(size, ALIGN); #endif /* Why 64? * Indeed, we should align it: * on 4 for 386 * on 16 for 486 * on 32 for 586, PPro - K6-III * on 64 for K7 (maybe for P3 too). * Because L1 and L2 caches are aligned on those values. * But I don't want to code such logic here! */ /* Why 32? * For AVX ASM. SSE / NEON needs only 16. * Why not larger? Because I did not see a difference in benchmarks ... */ /* benchmarks with P3 * memalign(64) + 1 3071, 3051, 3032 * memalign(64) + 2 3051, 3032, 3041 * memalign(64) + 4 2911, 2896, 2915 * memalign(64) + 8 2545, 2554, 2550 * memalign(64) + 16 2543, 2572, 2563 * memalign(64) + 32 2546, 2545, 2571 * memalign(64) + 64 2570, 2533, 2558 * * BTW, malloc seems to do 8-byte alignment by default here. */ #else ptr = malloc(size); #endif if(!ptr && !size) { size = 1; ptr= av_malloc(1); } #if CONFIG_MEMORY_POISONING if (ptr) memset(ptr, FF_MEMORY_POISON, size); #endif return ptr; }
如果不考慮上述程式碼中的一大堆巨集定義(即類似CONFIG_MEMALIGN_HACK這類的巨集都採用預設值0),av_malloc()的程式碼可以簡化成如下形式。
void *av_malloc(size_t size) { void *ptr = NULL; /* let's disallow possibly ambiguous cases */ if (size > (max_alloc_size - 32)) return NULL; ptr = malloc(size); if(!ptr && !size) { size = 1; ptr= av_malloc(1); } return ptr; }
可以看出,此時的av_malloc()就是簡單的封裝了系統函式malloc(),並做了一些錯誤檢查工作。
關於size_t
size _t 這個型別在FFmpeg中多次出現,簡單解釋一下其作用。size _t是為了增強程式的可移植性而定義的。不同系統上,定義size_t可能不一樣。它實際上就是unsigned int。為什麼要記憶體對齊?
FFmpeg記憶體分配方面多次涉及到“記憶體對齊”(memory alignment)的概念。這方面內容在IBM的網站上有一篇文章,講的挺通俗易懂的,在此簡單轉述一下。
程式設計師通常認為記憶體就是一個位元組陣列,每次可以一個一個位元組存取記憶體。例如在C語言中使用char *指代“一塊記憶體”,Java中使用byte[]指代一塊記憶體。如下所示。
但那實際上計算機處理器卻不是這樣認為的。處理器相對比較“懶惰”,它會以2位元組,4位元組,8位元組,16位元組甚至32位元組來存取記憶體。例如下圖顯示了以4位元組為單位讀寫記憶體的處理器“看待”上述記憶體的方式。
下面看一個例項,分別從地址0,和地址1讀取4個位元組到暫存器。
從程式設計師的角度來看,讀取方式如下圖所示。
而2位元組存取粒度的處理器的讀取方式如下圖所示。
4位元組存取粒度的處理器的讀取方式如下圖所示。
可以看出4位元組存取粒度的處理器從地址0讀取4個位元組一共讀取1次;從地址1讀取4個位元組一共讀取了2次。從地址1讀取的開銷比從地址0讀取多了一倍。由此可見記憶體不對齊對CPU的效能是有影響的。
av_realloc()
av_realloc()用於對申請的記憶體的大小進行調整。它的定義如下。
void *av_realloc(void *ptr, size_t size)
{
#if CONFIG_MEMALIGN_HACK
int diff;
#endif
/* let's disallow possibly ambiguous cases */
if (size > (max_alloc_size - 32))
return NULL;
#if CONFIG_MEMALIGN_HACK
//FIXME this isn't aligned correctly, though it probably isn't needed
if (!ptr)
return av_malloc(size);
diff = ((char *)ptr)[-1];
av_assert0(diff>0 && diff<=ALIGN);
ptr = realloc((char *)ptr - diff, size + diff);
if (ptr)
ptr = (char *)ptr + diff;
return ptr;
#elif HAVE_ALIGNED_MALLOC
return _aligned_realloc(ptr, size + !size, ALIGN);
#else
return realloc(ptr, size + !size);
#endif
}
預設情況下(CONFIG_MEMALIGN_HACK這些巨集使用預設值0)的程式碼:
void *av_realloc(void *ptr, size_t size)
{
/* let's disallow possibly ambiguous cases */
if (size > (max_alloc_size - 32))
return NULL;
return realloc(ptr, size + !size);
}
可以看出av_realloc()簡單封裝了系統的realloc()函式。
av_mallocz()
av_mallocz()可以理解為av_malloc()+zeromemory。程式碼如下。void *av_mallocz(size_t size)
{
void *ptr = av_malloc(size);
if (ptr)
memset(ptr, 0, size);
return ptr;
}
從原始碼可以看出av_mallocz()中呼叫了av_malloc()之後,又呼叫memset()將分配的記憶體設定為0。
av_calloc()
av_calloc()則是簡單封裝了av_mallocz(),定義如下所示。void *av_calloc(size_t nmemb, size_t size)
{
if (size <= 0 || nmemb >= INT_MAX / size)
return NULL;
return av_mallocz(nmemb * size);
}
從程式碼中可以看出,它呼叫av_mallocz()分配了nmemb*size個位元組的記憶體。
av_free()
av_free()用於釋放申請的記憶體。它的定義如下。
void av_free(void *ptr)
{
#if CONFIG_MEMALIGN_HACK
if (ptr) {
int v= ((char *)ptr)[-1];
av_assert0(v>0 && v<=ALIGN);
free((char *)ptr - v);
}
#elif HAVE_ALIGNED_MALLOC
_aligned_free(ptr);
#else
free(ptr);
#endif
}
預設情況下(CONFIG_MEMALIGN_HACK這些巨集使用預設值0)的程式碼:
void av_free(void *ptr)
{
free(ptr);
}
可以看出av_free()簡單的封裝了free()。av_freep()
av_freep()簡單封裝了av_free()。並且在釋放記憶體之後將目標指標設定為NULL。
void av_freep(void *arg)
{
void **ptr = (void **)arg;
av_free(*ptr);
*ptr = NULL;
}
雷霄驊 (Lei Xiaohua)
[email protected]
http://blog.csdn.net/leixiaohua1020
相關推薦
FFmpeg原始碼簡單分析:記憶體的分配和釋放(av_malloc()、av_free()等)
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:常見結構體的初始化和銷燬(AVFormatContext,AVFrame等)
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
ffmpeg 原始碼簡單分析 : av_read_frame()
此前寫了好幾篇ffmpeg原始碼分析文章,列表如下: ============================ ffmpeg中的av_read_frame()的作用是讀取碼流中的音訊若干幀或者視訊一幀。例如,解碼視訊的時
ffmpeg 原始碼簡單分析 : av_register_all()
此前寫了好幾篇ffmpeg原始碼分析文章,列表如下: ============================ 前一陣子看了一下ffmpeg的原始碼,並且做了一些註釋,在此貼出來以作備忘。 本文分析一下ffmpeg註冊
FFmpeg原始碼簡單分析:makefile
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:結構體成員管理系統-AVClass
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:avcodec_open2()
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:avformat_close_input()
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:av_write_frame()
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:avcodec_encode_video()
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:configure
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg的H.264解碼器原始碼簡單分析:概述
=====================================================H.264原始碼分析文章列表:【編碼 - x264】【解碼 - libavcodec H.264 解碼器】================================
FFmpeg的HEVC解碼器原始碼簡單分析:CTU解碼(CTU Decode)部分-TU
=====================================================HEVC原始碼分析文章列表:【解碼 -libavcodec HEVC 解碼器】==============================================
FFmpeg的H.264解碼器原始碼簡單分析:解碼器主幹部分
=====================================================H.264原始碼分析文章列表:【編碼 - x264】【解碼 - libavcodec H.264 解碼器】================================
FFmpeg的H.264解碼器原始碼簡單分析:熵解碼(Entropy Decoding)部分
=====================================================H.264原始碼分析文章列表:【編碼 - x264】【解碼 - libavcodec H.264 解碼器】================================
H264編碼器5( x264原始碼簡單分析:x264_slice_write() 與H264 編碼簡介)
x264原始碼簡單分析:x264_slice_write() 來自:https://blog.csdn.net/leixiaohua1020/article/details/45536607 H264 編碼簡介 https://blo
H264編碼器4( x264原始碼簡單分析:概述)
來自:https://blog.csdn.net/leixiaohua1020/article/details/45536607 ===================================================== H.264原始碼分析文章列表:
FFmpeg原始碼簡單分析 avio open2
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】=================================
FFmpeg原始碼簡單分析 avcodec encode video
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】=================================
Linux中的記憶體分配和釋放之slab分配器分析(完)
我們在上篇文章分析cache_grow()函式的時候涉及兩個函式,我們沒有細說。一個就是kmem_getpages()和kmem_freepages()函式,這兩個函式有3個引數。kmem_cahce_t:主要是把申請到的物件加到這個快取記憶體內 flag