How to Make FFmpeg Release Memory to the OS

FFmpeg relies on standard C runtime allocators that often retain freed memory pages in internal pools rather than releasing them back to the host operating system, causing memory usage to appear persistently high during long-running tasks. This article explains how to change this behavior by tuning system memory allocators, swapping to alternative memory managers like jemalloc, and constraining internal FFmpeg buffering settings to ensure unused memory is aggressively returned to the OS.

1. Tune the Default glibc Allocator

On Linux, the default GNU C Library (glibc) allocator avoids returning freed memory to the kernel via brk or munmap to optimize performance for future allocations. You can alter this behavior without recompiling FFmpeg by setting environment variables before executing your command.

  • MALLOC_TRIM_THRESHOLD_: Controls the maximum amount of freed memory glibc will hold before performing a trim operation to return it to the operating system. Lowering this value forces more frequent memory reclamation.
  • MALLOC_ARENA_MAX: Restricts the maximum number of memory allocation arenas created for multithreaded jobs, significantly reducing overall memory fragmentation.

Run your FFmpeg process with these variables prepended:

MALLOC_TRIM_THRESHOLD_=131072 MALLOC_ARENA_MAX=2 ffmpeg -i input.mp4 -c:v libx264 output.mp4

Setting MALLOC_TRIM_THRESHOLD_ to 131072 (128 KB) forces the system to decommit heap space much faster than the default threshold, which is typically several megabytes.

2. Replace the Memory Allocator with jemalloc

The default glibc allocator is not designed for aggressive memory deallocation. Using jemalloc—a general-purpose allocator created to prevent memory fragmentation and quickly purge unused pages—is the most effective way to force FFmpeg to return memory.

  1. Install jemalloc:
    • Debian/Ubuntu: sudo apt install libjemalloc-dev libjemalloc2
    • RHEL/CentOS: sudo dnf install jemalloc
  2. Run FFmpeg using LD_PRELOAD along with aggressive dirty-page decay settings:
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so \
MALLOC_CONF="dirty_decay_ms:1000,muzzy_decay_ms:1000" \
ffmpeg -i input.mp4 -c:v libx264 output.mp4
  • dirty_decay_ms:1000: Forces dirty, unused memory pages to be cleared and returned to the OS within 1 second.
  • muzzy_decay_ms:1000: Cleans and purges inactive pages from the OS memory map within 1 second.

3. Restrict FFmpeg Queues and Buffers

Memory that has never been released cannot be reclaimed by the OS. In complex or multithreaded pipelines, FFmpeg caches frames inside internal queues, ballooning memory usage before encoding completes. Restrict queue sizes and thread buffering to minimize the total memory footprint:

  • Reduce the demuxer thread queue:

    ffmpeg -thread_queue_size 16 -i input.mp4 -c:v libx264 output.mp4

    The default thread_queue_size is often 8 to 128 depending on the demuxer. Capping it to a lower value prevents decoded packets from accumulating in RAM.

  • Limit muxing queue limits:

    ffmpeg -i input.mp4 -max_muxing_queue_size 128 -c:v libx264 output.mp4

    This limits the buffer of packets waiting for the muxer when multiplexing multiple streams.

  • Lower probe and analysis buffers:

    ffmpeg -probesize 32M -analyzeduration 32M -i input.mp4 output.mp4

    For large or high-bitrate inputs, reducing the initial stream analysis limit ensures less input data is buffered during format detection.