FFmpeg内存管理

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

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

int add_something(int a, int b, int c) {
    int d = 4;
    int e = 5;
    int f = 6;
    return a + b + c + d + e + f;
}

int sub_something(int a, int b, int c) {
    int g = 7;
    int h = 8;
    int j = 9;
    return a + b + c - g - h - j;
}

int main() {
    int a = 1;
    int b = 2;
    int c = 3;
    int total;
    total = add_something(a, b, c);
    total = sub_something(a, b, c);
    return total;
}

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

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

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

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

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

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

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

1-1

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

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

1-2

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

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

扩展知识:函数调用,压栈,弹栈,会不断修改恢复 ebpesp所以栈内存能不断被重复使用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_freeav_freep ,其中 av_freep 函数接受的是二级指针,所以会把指针置为 NULL。这样做可以减少错误。


版权所属 xianwanzhiyin.net 罗上文 2022 all right reserved,powered by Gitbook该文件修订时间: 2022-08-30 19:51:22

results matching ""

    No results matching ""