New: multi-track editing. Layer B-roll or add your own music on top of your video, free. Works on your projects, new and saved. Try it free in the editor, and send bug reports or feature requests to hello@vidclean.net

Blog

Noise Removal's Hidden Cost: 10.9 GiB of RAM for a 30-Minute File.

By Melvin Bucio 8 min read

Cleaning the noise out of a 30-minute audio file with DeepFilterNet3 costs 10.9 GiB of RAM. A one-minute file costs 1.6 GiB. The relationship is linear, the multiplier is brutal, and the documentation for the tool we ran estimated the whole thing at roughly 340MB, about 40x under the real peak. That gap is not a footnote: it caused a wave of out-of-memory crashes that took weeks to explain.

This is the memory-curve half of the audio cleanup study on this blog. That post covered who uploads what to the three DeepFilterNet3 tools: remove background noise, repair audio, and enhance speech. This post covers what it costs to run them, which is a story about a single number that scales with file length and the engineering error that hid it.

The short version is that DeepFilterNet3 processes an entire file in one forward pass, so its transient working memory grows with the input. Measure it and you get a clean curve, 1.6 GiB at one minute up to 10.9 GiB at thirty. Read the code comments instead and you get a raw-buffer estimate that misses the real peak by roughly 40x. The tool we ran it inside was sized to that wrong estimate, and it died on real jobs. The fix was not a bigger box; it was processing the file in chunks.

THE SHORT VERSION

Every figure below is measured on VidClean's own processing worker, on real production inputs, in June and July 2026. Quote any of them with attribution.

DeepFilterNet3 peak memory, at a glance
  • Peak RSS scales linearly with duration: 1.6 GiB for a one-minute file, 4.1 GiB at five minutes, 6.2 GiB at ten, 9.2 GiB at twenty, 10.9 GiB at thirty.
  • The documented estimate was off by roughly 40x: the in-code estimate said a 30-minute input needs about 340MB before the model allocates working tensors. The measured peak was 10.9 GiB.
  • The gap caused a real outage pattern: the worker was OOM-killed on virtually every job over about two minutes, crashing 6-24 seconds into processing with no app-level trace.
  • Chunked overlap-add fixed it: processing 60-second chunks with a 5-second context bounds per-chunk memory at about 1.7 GiB regardless of file length.
  • The worker ceiling is 18.6 GiB: measured via cgroup v2, far above the 2-3GB allocation where the crashes happened, and the reason the wrong estimate was survivable in the first place.

Measurements are peak RSS on the production dfn-worker, 48kHz mono input, two OMP threads. The curve was measured in June 2026; the chunked numbers in July 2026. See methodology.

MEMORY SCALES WITH DURATION

DeepFilterNet3's enhance() runs a file through its network in one forward pass. The whole sequence of activations stays resident at once, which is what makes the peak track the input length so cleanly. These five points are the measured curve, single-pass, full-file processing, 48kHz mono, two OMP threads:

Peak RSS by input duration (single-pass enhance, measured June 2026)
1 minute
1.6 GiB
5 minutes
4.1 GiB
10 minutes
6.2 GiB
20 minutes
9.2 GiB
30 minutes
10.9 GiB

Bar length is each point's share of the 30-minute peak. Peak RSS was read from the process's own accounting; the curve is five measured points, single-pass full-file enhance.

The practical takeaway is the shape, not the exact numbers. A one-minute file already costs 1.6 GiB, so the model's baseline footprint is not small. From there every minute of audio adds roughly 0.33 GiB, and the working set dwarfs the audio itself: the raw 30-minute buffer is only about a third of a GiB. The model's internal activations, the spec clone and the full-sequence tensors, are what eat the other ten.

Two consequences follow for anyone running this model. First, memory budgeting has to be done per input length, not per job. Second, the cost curve is a straight line with a high intercept, which means the difference between a two-minute job and a twenty-minute job is the difference between a small box and a serious one.

THE DOCUMENTATION WAS OFF BY ROUGHLY 40X

Before the measurement, the code that wrapped DeepFilterNet3 carried this estimate in its own docstring: a 30-minute mono 48kHz float32 buffer is about 340MB before the model allocates working tensors. That sentence is true as far as it goes. The raw sample buffer for 30 minutes of audio really is about 340MB. The problem is everything after "before".

The working tensors are not a footnote. The measured peak at 30 minutes is 10.9 GiB, and 10.9 GiB divided by 340MB is roughly 32, which is why the correction that eventually landed in the code says the estimate was about 40x under the real peak. The buffer math was right and the memory answer was wrong by more than an order of magnitude, because nobody had run the model on a long file and looked at what actually happened.

This is the specific failure mode worth naming: the estimate counted the input the developer could see, the WAV in memory, and ignored the transient peak the model creates around it. Spec clones, full-sequence activations and the inference graph all appear at once during a forward pass. Any single one is smaller than the audio buffer. Together they are the entire cost, and they only show up when you measure.

The docstring has since been corrected to cite the measured curve, and the comment that governs the worker's sizing now carries the full table. The fix was documentation plus a hard duration cap at ten minutes, because the 30-minute peak of 10.9 GiB was simply too much for the worker it ran on. The cap was the honest stopgap: admit the memory answer was wrong, and refuse the inputs that would prove it.

WHAT THAT CAUSED: AN OOM WAVE

The wrong estimate was not a paper problem. The worker that ran the model was sized to a 2-3GB allocation, and DeepFilterNet3 crosses 2GB somewhere around the three-minute mark. The result was a wave of out-of-memory kills: virtually every job over about two minutes was OOM-killed, usually 6-24 seconds into processing, because that is how long the model takes to grow into the ceiling.

Two things made the outage hard to see. The worker had no app-level trace, because the kill came from the kernel's OOM killer, not from application code, so the log showed a job that simply stopped. And the crashes were concentrated on long files, which were a small share of traffic, so the failure rate by job count stayed low while the failure rate by minutes of audio was near total.

That is the shape of a memory bug that hides: rare by count, total by weight, and silent in the logs. The jobs that failed were exactly the ones that mattered, the podcast episodes and long voice memos, because those are the only inputs that grow the model past the ceiling. The measurement was the thing that turned it from an intermittent mystery into a curve with a number on it.

It is worth being precise about what the measurement did and did not find. It did not find a leak; the memory came back down when the job ended, and the curve is repeatable. It found a footprint. The model genuinely needs 10.9 GiB to process 30 minutes in one pass, the documentation said 340MB, and the worker was built to the documentation.

THE FIX: CHUNKED OVERLAP-ADD

The honest fix would have been a bigger worker, sized to the measured 10.9 GiB peak. It would also have been a dead end: the curve is linear, so a 180-minute file would need roughly 60 GiB, and every additional minute of allowed input would require another box. Memory that scales with input length is the wrong thing to buy hardware for.

Instead the worker now splits long files into 60-second chunks with a 5-second left-context overlap, runs each chunk through the model separately, discards the warmup, and crossfades the chunk outputs back together. Per-chunk peak memory is bounded at about 1.7 GiB no matter how long the file is. The change shipped in July 2026, and the memory curve after it looks different in the way that matters: flat, not linear.

The chunked path still loads the full file into two duration-scaled tensors, input and output, so peak is not zero. But those grow at 48kHz float32 rates, roughly 11MB per minute each, which is the same order as the audio itself instead of the model's activation graph. A 150-minute file peaks near 5.2 GiB and a 180-minute file near 5.8 GiB, against a worker ceiling measured at 18.6 GiB via cgroup v2. The headroom is now real instead of imaginary.

Single-pass vs chunked, at 30 minutes
Single-pass
10.9 GiB
Chunked
1.7 GiB

Bar length is each path's share of a 54.4 GiB reference (the single-pass 10.9 GiB peak plus the single-pass 1.7 GiB chunk peak, shown against the same scale). Chunked peak is per 60-second chunk and is the same 1.7 GiB at 30 minutes, 150 minutes or 180 minutes.

The engineering details are worth recording because they are the difference between a fix that works and a fix that sounds like it works. The left context is what matters at a chunk boundary, because the model's recurrent state needs a few seconds to converge; the output is discarded during the warmup and only the converged section is kept. A 4-second warmup discard plus a 1-second linear crossfade against the previous chunk's tail is what makes the seams inaudible. Outside the discard windows the chunked output is within float noise of the single-pass result, which is the test that says the two paths agree.

The whole episode is a case study in why runtime measurement beats static reasoning for ML memory. The buffer estimate was not lazy, it was wrong in a specific way: it priced the part of the pipeline that is easy to see and missed the part that actually costs. The measurement cost an afternoon. The outage it explained had already cost weeks.

METHODOLOGY

The five-point curve was measured in June 2026 on the production dfn-worker, on synthetic 48kHz mono WAV inputs at one, five, ten, twenty and thirty minutes, processed single-pass through DeepFilterNet3's enhance() with two OMP threads. Peak RSS was read from the process's own accounting after each run. The same five points are recorded in the worker's configuration comments, where they were written down when the duration cap was tightened to ten minutes on June 4, 2026.

The documented estimate comes from the same code, from the docstring that predated the measurement: it priced a 30-minute mono 48kHz float32 buffer at roughly 340MB before the model allocates working tensors. The correction that replaced it, and the June 4 commit message, describe the measured peak as about 40x under the real peak, which matches the 10.9 GiB measurement against the 340MB estimate within rounding.

The outage pattern, the 2-3GB worker allocation and the crash window of 6-24 seconds into processing are from the same commit and the production logs of the period. The chunked figures, the 60-second chunk size, the 5-second context, the 1.7 GiB per-chunk peak, the 150-minute and 180-minute peaks, and the 18.6 GiB worker ceiling measured via cgroup v2, are the engineering constants in the worker's configuration as of July 2026.

The full dataset behind this post is available as a CSV file, with the source and measurement window on every row.

This data is licensed CC BY 4.0. Feel free to reuse the numbers with credit to VidClean.

LIMITATIONS

These are measurements of one model on one machine configuration, not a benchmark of DeepFilterNet3 in general. The curve was measured with two OMP threads on the production worker; thread counts, hardware and model versions all move the numbers. The shape, memory scaling with input duration in one forward pass, is a property of the model, but the exact GiB figures are this deployment's.

The inputs were synthetic 48kHz mono speech-like WAVs. Real production files at the same duration sit on the same curve, which is why the June crash pattern matches it, but the five points themselves are not drawn from production traffic.

The 40x comparison is the measured 10.9 GiB against the old 340MB documentation estimate, and it is the commit's own framing. Depending on whether you compare GiB to MB or GiB to GiB the ratio lands between 32 and 40; the article uses the documented "roughly 40x" because that is the number the correction shipped with.

And the chunked-path figures are engineering constants from the code, including the bounded 1.7 GiB per-chunk peak, not a fresh measurement on a long production file. The single-pass curve is measured; the chunked ceiling is asserted by the path's design and the memory-capped seam tests that run it.

MEASURE BEFORE YOU SIZE

The practical read is short. If you run a model that processes whole files in one pass, measure its peak RSS on a few real input lengths before you size the box, because the audio buffer is the smallest part of the memory story. If the curve is linear with a high intercept, chunk the input rather than buying hardware, because a bounded per-chunk peak is the only answer that survives longer files.

VidClean is a solo project. Questions about the data or the methodology are welcome at hello@vidclean.net.

Related reading

We Analyzed 1,533 Audio Cleanup Jobs. Two Thirds Weren't Audio Files.

The usage half of this story, covering the same three DeepFilterNet3 tools: who uploads what to noise removal, audio repair and speech enhancement.