• FFmpeg内存管理


    FFmpeg 的社群来了,想加入微信社群的朋友请购买《FFmpeg原理》VIP版 电子书,里有更高级的内容与答疑服务。


    FFmpeg 是一个 C程序的项目,C语言是需要手动管理内存的。内存管理有一个技巧,只要你分清楚这个变量是在栈上,还是在堆上的就可以了。在栈上的变量不需要手动释放,而在堆上的变量需要自己释放。

    下面通过一个实例, 通过 反汇编 来讲解一下 栈变量 为什么不需要自己释放,代码如下:

    1. int add_something(int a, int b, int c) {
    2. int d = 4;
    3. int e = 5;
    4. int f = 6;
    5. return a + b + c + d + e + f;
    6. }
    7. int sub_something(int a, int b, int c) {
    8. int g = 7;
    9. int h = 8;
    10. int j = 9;
    11. return a + b + c - g - h - j;
    12. }
    13. int main() {
    14. int a = 1;
    15. int b = 2;
    16. int c = 3;
    17. int total;
    18. total = add_something(a, b, c);
    19. total = sub_something(a, b, c);
    20. return total;
    21. }

    首先,一个线程在大多数系统上会默认有1M的栈内存,这个大小可以通过配置修改。也就是一个线程创建的时候,默认就会先申请1M的栈内存。

    有些同学可能会觉得,1M 是不是有点小,如果定义了太多的局部变量,用完这 1M 怎么办?用完了就会报错,如果你的程序访问了 1M 地址之外的内存,就会报 segment fault 错误。

    我们知道,函数调用会先 压栈,然后再弹栈,但是还有一个地方也会用到栈内存,就是局部变量,你每创建一个局部变量,栈就会变得更小一点。

    首先,栈内存的访问通常是由两个寄存器控制的。如下:

    1,esp ,栈寄存器,存储的是当前的栈地址,会随着代码运行不断地变化

    2,ebp,栈顶寄存器,存储的是栈顶的地址,变化较少。

    现在反汇编一下上面的代码,如下:

    可以看到,进入 add_something 函数的时候,入口那里,有个 sub 指令,这个指令会直接切走一块栈内存,给 局部变量用。也不仅仅是给局部变量用,也有其他用途。

    我们注意看,现在 EBP 寄存器的值是 0x00B5F630,也就是 d 变量的地址是 0x00B5F630 - 4 = 0x00B5F62C ,为什么我们不需要用 free 函数释放 0x00B5F62C 地址的内存呢?我们继续断点,进入 sub_something 函数,就清楚了,如下:

    可以看到,g 变量的内存地址也是 0x00B5F630 - 4 = 0x00B5F62C,所以当 sub_something 执行的时候,之前 add_something 函数里面的 局部变量 d,e,f 指向的内存就会被覆盖。

    所以栈内存,是一个可以不断重复使用的内存。所以局部变量不需要释放,只要离开了函数的作用域,之前的局部变量内存就会被重新覆盖使用。

    扩展知识:函数调用,压栈,弹栈,会不断修改恢复 ebp 跟 esp所以栈内存能不断被重复使用main 也是一个函数,main 的外面其实还有一层函数调它。


    下面开始介绍一下 FFmpeg 跟内存相关的函数,如下:

    1,av_frame_alloc,创建一个 AVFrame 结构的堆内存。对应 av_frame_free

    2,av_packet_alloc,创建一个 AVPacket 结构的堆内存。对应 av_packet_free

    3,avformat_alloc_context,创建一个 AVFormatContext 结构的堆内存。对应 avformat_close_input 或者 avformat_free_context

    4,avcodec_alloc_context3,创建一个 AVCodecContext 结构的堆内存。对应 avcodec_close 或者 avcodec_free_context

    5,av_malloc,申请内存。对应 av_free 跟 av_freep ,其中 av_freep 函数接受的是二级指针,所以会把指针置为 NULL。这样做可以减少错误。

  • 相关阅读:
    Win7缺失dll文件如何修复?Win7计算机丢失dll文件怎么办
    Iptables扩展模块-connlimit 限制并发连接数
    【Spring 学习系列】Bean 的生命周期之初始化与销毁
    Linus:我终于在 M2 芯片的 MacBook 上发布了 Linux 最新版本!
    【Linux升级之路】7_进程信号
    PTA乙级 1105 链表合并——25分
    Vmware Workstation安装说明
    速盾网络:cdn加速技术和云计算的区别
    Dubbo Invoker
    ThreadLocal详解
  • 原文地址:https://blog.csdn.net/u012117034/article/details/127760831