做付费网站,模版网站如何优化,南宁网站建设找建站通,网页设计代码模板百度模板一、av_malloc函数分析
#xff08;一#xff09;av_malloc函数的声明
av_malloc函数的声明放在在FFmpeg源码#xff08;本文演示用的FFmpeg源码版本为5.0.3#xff0c;该ffmpeg在CentOS 7.5上通过10.2.1版本的gcc编译#xff09;的头文件libavutil/mem.h中#xff1a;…一、av_malloc函数分析
一av_malloc函数的声明
av_malloc函数的声明放在在FFmpeg源码本文演示用的FFmpeg源码版本为5.0.3该ffmpeg在CentOS 7.5上通过10.2.1版本的gcc编译的头文件libavutil/mem.h中
/*** 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); 根据注释可以了解到该函数作用是分配一个适合所有内存访问的内存块(包括动态数组如果CPU上可用)。形参size要分配的内存块的字节大小。返回值指向分配块的指针如果无法申请内存则返回NULL。 宏定义av_malloc_attrib也被定义在libavutil/mem.h中
/*** def av_malloc_attrib* Function attribute denoting a malloc-like function.** see a hrefhttps://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-g_t_0040code_007bmalloc_007d-function-attribute-3251Function attribute malloc in GCCs documentation/a*/#if AV_GCC_VERSION_AT_LEAST(3,1)#define av_malloc_attrib __attribute__((__malloc__))
#else#define av_malloc_attrib
#endif
这里用attribute指定__malloc__属性表示这样标记的函数av_malloc函数返回的块不得包含任何指向其他对象的指针。这样做的目的是帮助编译器估计哪些指针可能指向同一个对象该属性告诉GCC它不必担心函数返回的对象可能包含指向它正在跟踪的其他对象的指针。具体可以参考GCC: __attribute__((malloc)) 宏定义av_malloc_attrib也被定义在libavutil/mem.h中
/*** def av_alloc_size(...)* Function attribute used on a function that allocates memory, whose size is* given by the specified parameter(s).** code{.c}* void *av_malloc(size_t size) av_alloc_size(1);* void *av_calloc(size_t nmemb, size_t size) av_alloc_size(1, 2);* endcode** param ... One or two parameter indexes, separated by a comma** see a hrefhttps://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-g_t_0040code_007balloc_005fsize_007d-function-attribute-3220Function attribute alloc_size in GCCs documentation/a*/#if AV_GCC_VERSION_AT_LEAST(4,3)#define av_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__)))
#else#define av_alloc_size(...)
#endif
这里用attribute指定alloc_size属性用于告诉编译器函数返回值指向的内存其大小是由alloc_size中的参数指定主要用于提高__builtin_object_size的正确性。具体参考GCC __atrribute__
然后宏定义用到了变参__VA_ARGS__可以参考C 语言 define 变参__VA_ARGS__使用 所以函数声明void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1) 等价于
void *av_malloc(size_t size) __attribute__((__malloc__)) __attribute__((alloc_size(1)))
简单来讲__attribute__只是让代码优化得更好而已我们可以忽略。 二av_malloc函数的实现原理
av_malloc函数定义在libavutil/mem.c中
#define HAVE_POSIX_MEMALIGN 1
#define HAVE_ALIGNED_MALLOC 0
#define HAVE_MEMALIGN 1
#define HAVE_AVX512 0
#define HAVE_AVX 0
#define CONFIG_MEMORY_POISONING 0
#define ALIGN (HAVE_AVX512 ? 64 : (HAVE_AVX ? 32 : 16))static atomic_size_t max_alloc_size ATOMIC_VAR_INIT(INT_MAX);void *av_malloc(size_t size)
{void *ptr NULL;if (size atomic_load_explicit(max_alloc_size, memory_order_relaxed))return NULL;#if HAVE_POSIX_MEMALIGNif (size) //OS X on SDK 10.6 has a broken posix_memalign implementationif (posix_memalign(ptr, ALIGN, size))ptr NULL;
#elif HAVE_ALIGNED_MALLOCptr _aligned_malloc(size, ALIGN);
#elif HAVE_MEMALIGN
#ifndef __DJGPP__ptr memalign(ALIGN, size);
#elseptr 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 dont 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.*/
#elseptr malloc(size);
#endifif(!ptr !size) {size 1;ptr av_malloc(1);}
#if CONFIG_MEMORY_POISONINGif (ptr)memset(ptr, FF_MEMORY_POISON, size);
#endifreturn ptr;
} 去掉一大堆其它东西av_malloc函数的核心实现就是
void *av_malloc(size_t size)
{//...void *ptr NULL;if (posix_memalign(ptr, ALIGN, size)){ptr NULL;}//...return ptr;}
可以看到其本质就是调用了posix_memalign函数该函数是Linux下内存对齐的函数其作用是分配size大小的字节并将分配的内存地址存放在ptr中。分配的内存的地址将是ALIGN的倍数且必须是2的幂次方和sizeof(void*)的倍数。如果size为0则函数返回NULL或一个唯一的指针值以便可以成功传递给free函数。如果分配成功返回0该函数跟malloc函数相近。mallocposix_memalign函数跟mallocmalloc函数的区别是 malloc函数总是返回8字节对齐的内存地址在64bits上是16字节对齐而对于更大的边界例如页面需要动态的对齐的时候就可以选择posix_memalign函数。具体可以参考posix_memalign(3) — Linux manual page 总结av_malloc函数作用是分配一个适合所有内存访问的内存块形参size为 要分配的内存块的字节大小。其底层实现就是调用了posix_memalign函数。 二、av_mallocz函数分析
一av_mallocz函数的声明
av_mallocz函数的声明放在在FFmpeg源码的头文件libavutil/mem.h中
/*** Allocate a memory block with alignment suitable for all memory accesses* (including vectors if available on the CPU) and zero all the bytes of the* block.** param size Size in bytes for the memory block to be allocated* return Pointer to the allocated block, or NULL if it cannot be allocated* see av_malloc()*/
void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); 根据注释可以了解到该函数作用是分配一个适合所有内存访问的内存块 (包括CPU上可用的动态数组)并将块的所有字节归零。形参size要分配的内存块的字节大小。 返回值指向已分配块的指针如果不能分配则为NULL。 二av_mallocz函数的实现原理
av_mallocz函数定义在libavutil/mem.c中
void *av_mallocz(size_t size)
{void *ptr av_malloc(size);if (ptr)memset(ptr, 0, size);return ptr;
} 可以看到其核心就是调用了av_malloc函数分配内存块随后调用memset函数将该内存块的所有字节清零。因为av_mallocz函数会将内存块清零相当于对内存块进行一个初始化操作。所以在FFmpeg源码中一般使用av_mallocz而不会直接使用av_malloc函数。 三、av_free函数分析
一av_free函数的声明
av_free函数的声明放在在FFmpeg源码的头文件libavutil/mem.h中
/*** Free a memory block which has been allocated with a function of av_malloc()* or av_realloc() family.** param ptr Pointer to the memory block which should be freed.** note ptr NULL is explicitly allowed.* note It is recommended that you use av_freep() instead, to prevent leaving* behind dangling pointers.* see av_freep()*/
void av_free(void *ptr); 根据注释可以了解到该函数作用是释放av_malloc()/av_mallocz()函数分配的内存块。形参ptr指向应该释放的内存块的指针。 二av_free函数的实现原理
av_free函数定义在libavutil/mem.c中
void av_free(void *ptr)
{
#if HAVE_ALIGNED_MALLOC_aligned_free(ptr);
#elsefree(ptr);
#endif
}
可以看到其核心就是调用free函数释放空间。 四、av_freep函数分析
一av_freep函数的声明
av_freep函数的声明放在在FFmpeg源码的头文件libavutil/mem.h中
/*** Free a memory block which has been allocated with a function of av_malloc()* or av_realloc() family, and set the pointer pointing to it to NULL.** code{.c}* uint8_t *buf av_malloc(16);* av_free(buf);* // buf now contains a dangling pointer to freed memory, and accidental* // dereference of buf will result in a use-after-free, which may be a* // security risk.** uint8_t *buf av_malloc(16);* av_freep(buf);* // buf is now NULL, and accidental dereference will only result in a* // NULL-pointer dereference.* endcode** param ptr Pointer to the pointer to the memory block which should be freed* note *ptr NULL is safe and leads to no action.* see av_free()*/
void av_freep(void *ptr); 根据注释可以了解到该函数作用是释放av_malloc()/av_mallocz()函数分配的内存块并设置指向它的指针为NULL 。 二av_freep函数的实现原理
av_freep函数定义在libavutil/mem.c中
void av_freep(void *arg)
{void *val;memcpy(val, arg, sizeof(val));memcpy(arg, (void *){ NULL }, sizeof(val));av_free(val);
} 可以看到其核心就是调用了av_free函数释放空间。然后av_freep函数可以避免仅使用av_free函数释放空间后出现的悬挂指针避免安全风险。所以av_freep函数比仅使用av_free函数更安全。 五、编写测试例子来理解av_mallocz函数和av_freep函数的使用
通过上述的讲解相信大家已经了解了FFmpeg源码中这几个内存相关的函数也理解了FFmpeg 源码中C语言的设计艺术。就拿FFmpeg的内存相关的函数来讲其设计艺术在于av_mallocz函数申请、分配内存后还会对该内存块进行初始化清零的操作av_freep函数在释放内存块空间后会把指针指向NULL。我们可以把av_mallocz函数和av_freep函数从FFmpeg源码中抽取出来移植到我们自己的C语言代码中使用。这样在不依赖FFmpeg库文件的情况下我们也能使用FFmpeg里面的函数。这就是最简单的对FFmpeg裁剪。 编写测试例子main.c在CentOS 7.5上通过10.2.1版本的gcc可以成功编译 :
#include stdlib.h
#include string.h
#include stdio.h
#include stdint.h
#include stdatomic.h
#include limits.h#define HAVE_POSIX_MEMALIGN 1
#define HAVE_ALIGNED_MALLOC 0
#define HAVE_MEMALIGN 1
#define HAVE_AVX512 0
#define HAVE_AVX 0
#define CONFIG_MEMORY_POISONING 0
#define ALIGN (HAVE_AVX512 ? 64 : (HAVE_AVX ? 32 : 16))static atomic_size_t max_alloc_size ATOMIC_VAR_INIT(INT_MAX);#ifdef __GNUC__
# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ (x) || __GNUC__ (x) __GNUC_MINOR__ (y))
# define AV_GCC_VERSION_AT_MOST(x,y) (__GNUC__ (x) || __GNUC__ (x) __GNUC_MINOR__ (y))
#else
# define AV_GCC_VERSION_AT_LEAST(x,y) 0
# define AV_GCC_VERSION_AT_MOST(x,y) 0
#endif#if AV_GCC_VERSION_AT_LEAST(3,1)#define av_malloc_attrib __attribute__((__malloc__))
#else#define av_malloc_attrib
#endif#if AV_GCC_VERSION_AT_LEAST(4,3)#define av_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__)))
#else#define av_alloc_size(...)
#endifvoid *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1);
void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1);
void av_free(void *ptr);
void av_freep(void *ptr);void *av_malloc(size_t size)
{void *ptr NULL;if (size atomic_load_explicit(max_alloc_size, memory_order_relaxed))return NULL;#if HAVE_POSIX_MEMALIGNif (size) //OS X on SDK 10.6 has a broken posix_memalign implementationif (posix_memalign(ptr, ALIGN, size))ptr NULL;
#elif HAVE_ALIGNED_MALLOCptr _aligned_malloc(size, ALIGN);
#elif HAVE_MEMALIGN
#ifndef __DJGPP__ptr memalign(ALIGN, size);
#elseptr 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 dont 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.*/
#elseptr malloc(size);
#endifif(!ptr !size) {size 1;ptr av_malloc(1);}
#if CONFIG_MEMORY_POISONINGif (ptr)memset(ptr, FF_MEMORY_POISON, size);
#endifreturn ptr;
}void *av_mallocz(size_t size)
{void *ptr av_malloc(size);if (ptr)memset(ptr, 0, size);return ptr;
}void av_free(void *ptr)
{
#if HAVE_ALIGNED_MALLOC_aligned_free(ptr);
#elsefree(ptr);
#endif
}void av_freep(void *arg)
{void *val;memcpy(val, arg, sizeof(val));memcpy(arg, (void *){ NULL }, sizeof(val));av_free(val);
}int main()
{uint8_t *pBuf av_mallocz(128);if(pBuf){strcpy(pBuf, hello world);printf(%s\n, pBuf);av_freep(pBuf);if(!pBuf){printf(pBuf is free\n);}}return 0;
} 使用gcc编译运行输出如下 六、参考文章
《FFmpeg5.0源码阅读——内存分配和释放》