1 av_malloc()
av_malloc() 声明:
- 所属库:libavutil,该库是ffmpeg的功能库,提供了线程,内存,文件,加密等功能
- 头文件:libavutil/mem.h
- 该函数作用在于给对象分配内存块,并且是内存对齐的
- 该函数由两个宏av_malloc_attrib && av_alloc_size(1)指定了一些编译器属性,作用如后面所描述,更详细的描述见 FFMPEG4.1源码分析之 内存分配
/**
* Allocate a memory block with alignment suitable for all memory accesses
* (including vectors if available on the CPU).
*
* @param size Size in bytes for the memory block to be allocated
* @return Pointer to the allocated block, or `NULL` if the block cannot
* be allocated
* @see av_mallocz()
*/
void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1);
- av_malloc_attrib是一个宏定义,如果是在编译器GCC3.1及以上版本的情况下,给方法av_malloc增加属性 __attribute__((__malloc__)),该属性指示编译器按照malloc函数来对待本函数,并且可以对其实施相应的优化措施。后续在研究ffmpeg中内存分配与管理的源码之后,会再尝试写一篇文章详细介绍。此时,先给出几个网上关于该属性的描述相关网址:http://www.keil.com/support/man/docs/armcc/armcc_chr1359124975555.htm; https://stackoverflow.com/questions/18485447/gcc-attribute-malloc; https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-g_t_0040code_007bmalloc_007d-function-attribute-3251
/** * @def av_malloc_attrib * Function attribute denoting a malloc-like function. * * @see <a href="https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-g_t_0040code_007bmalloc_007d-function-attribute-3251">Function attribute `malloc` in GCC's documentation</a> */ #if AV_GCC_VERSION_AT_LEAST(3,1) #define av_malloc_attrib __attribute__((__malloc__)) #else #define av_malloc_attrib #endif
- av_alloc_size(1)也是一个宏定义,如果是在编译器GCC4.3及以上版本的情况下,给方法增加一个属性__attribute__((alloc_size(1))),告知编译器av_malloc(size_t size)方法的第一个参数,也即size是要分配的空间大小,关于__attribute__((alloc_size(__VA_ARGS__)))属性的详细描述可以见:https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-g_t_0040code_007balloc_005fsize_007d-function-attribute-3220
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;
#if 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为0时,将分配一个字节的空间
size = 1;
ptr= av_malloc(1);
}
#if CONFIG_MEMORY_POISONING
if (ptr)
memset(ptr, FF_MEMORY_POISON, size);
#endif
return ptr;
}
- 该函数在不同的宏作用下使用了不同的内存分配函数,优先级为posix_memalign() ->_aligned_malloc() -> memalign() -> malloc()。这些宏定义在文件config.h中,这个文件不属于ffpmeg的任何库,这个是ffmpeg源码编译时,configure命令生成的配置文件,在不同的环境下,config.h文件中的宏定义值是不一样的。
- 就我当前的编译环境Windows系统,VisualStudio2013update5来说,这几个宏定义分别为如下源代码所示,因此将会使用_aligned_malloc()方法进行内存分配,而该方法定义在如下平台相关的文件中,见下图,另外该方法的详细描述见:MicroSoft Docs:_aligned_malloc
#define HAVE_POSIX_MEMALIGN 0 #define HAVE_ALIGNED_MALLOC 1 #define HAVE_MEMALIGN 0 __DJGPP__ 未定义
-
内存对齐:上述几个函数除了malloc外都具有内存对齐功能,另外还有一个宏ALIGN ,其根据另外两个宏HAVE_AVX512 和HAVE_AVX来决定是按多少位对齐,而HAVE_AVX和HAVE_AVX512指示环境中是否可以使用AVX CPU指令集和AVX512 CPU扩展指令集,能使用更高级的指令集意味着可以使用的寄存器大小会变大,因此对齐的数据位数也会变大。关于AVX与AVX512的详细描述见wikipedia:AVX指令集, AVX512
#define ALIGN (HAVE_AVX512 ? 64 : (HAVE_AVX ? 32 : 16))
-
注意到当size=0时,将分配一个字节的空间,这儿是令我奇怪的一点,为什么此处不直接返回NULL就行了?突然又想到在C/C++的空结构体/空类都会占据一个字节以作占位符,见如下示例代码以及结果展示。猜测这儿应该也是起同样的作用。
#include <stdio.h> struct EmptyStruct{}; class EmptyClass{}; int main(int argc, char* argv[]) { printf("EmptyStruct'size is %d\n", sizeof(EmptyStruct)); printf("EmptyClass'size is %d\n", sizeof(EmptyClass)); getchar(); return 0; }
-
最后,宏CONFIG_MEMORY_POISONING决定了分配后的数据是否需要使用数据填充,根据该宏的名称也知道是“毒化,中毒”的意思,通常我们分配内存后一般都是使用0去初始化这块儿内存,但是ffmpeg中如果配置了上述宏定义,那么会使用FF_MEMORY_POISON指定的0x2a去填充分配空间的每个字节。当然,就我目前的环境而言,config.h文件中的 CONFIG_MEMORY_POISONING 被定义为0,也即不进行内存“毒化”。
#define CONFIG_MEMORY_POISONING 0 #define FF_MEMORY_POISON 0x2a
2 av_mallocz()
av_mallocz() 声明:
void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1);
av_mallocz() 源码:
void *av_mallocz(size_t size)
{
void *ptr = av_malloc(size); 使用av_malloc分配内存
if (ptr)
memset(ptr, 0, size); 将分配的内存块所有字节置0
return ptr;
}