toolgarden.xyz
中文
browsermemoryBlob URL

Why Must You Revoke URL.createObjectURL() URLs After Use?

Understand Blob URL ownership, garbage-collection boundaries and download races, and manage previews with an explicit cleanup function.

ToolGarden tools prioritize browser-local processing, so files and text do not need to be uploaded to a server.

Published October 10, 20268 min readBy ToolGarden

URL.createObjectURL(blob) returns a browser-managed resource address rather than encoded file contents. Losing the local string variable does not revoke that address. A long-running tool that generates previews needs a policy for retiring obsolete results and releasing their URLs.

A short address can retain a large resource

Think of three layers: the application string, the browser URL registration and the backing Blob data. Storage may be memory-backed or otherwise managed by the browser. String length therefore says little about the retained resource cost.

Two createObjectURL calls on the same Blob produce independent addresses. They need not duplicate all underlying bytes, but revoking one does not retire the other. Keep a tracked URL per result instead of generating fresh addresses during every render.

What revocation does

ActionEffectDoes not guarantee
revokeObjectURL(url)Removes this address mappingDeletion of downloaded files
Drop a Blob referenceRemoves one JS retaining pathRevocation of other URLs
Remove a media elementEnds that UI consumerImmediate native-cache release
Close the documentUsually releases its URL registrationsCleanup during a long session

Do not start a new read from a revoked address. Revocation is not a forced garbage collection call: other Blob references, decoded surfaces or active consumers may retain resources. A process-memory number need not fall immediately. Evaluate repeated-use behavior rather than expecting an instant drop after one function call.

Make the result own its preview

The following example owns one image and one download link and returns an idempotent disposer. It expects a PNG Blob. Keep the disposer with that result and call it when replacing, clearing or unmounting the view. Calling it immediately after mounting would invalidate the URL before asynchronous consumers are ready.

function mountBlobPreview(blob: Blob, host: HTMLElement): () => void {
  const url = URL.createObjectURL(blob);
  const image = document.createElement('img');
  const download = document.createElement('a');
  image.alt = 'Generated image preview';
  image.src = url;
  download.href = url;
  download.download = 'result.png'; // This example expects a PNG Blob.
  download.textContent = 'Download PNG';
  host.append(image, download);

  let disposed = false;
  return () => {
    if (disposed) return;
    disposed = true;
    image.removeAttribute('src');
    download.removeAttribute('href');
    image.remove();
    download.remove();
    URL.revokeObjectURL(url);
  };
}

// Keep this disposer with the current result.
const disposePreview = mountBlobPreview(pngBlob, resultContainer);
// Call disposePreview() when this result is retired or the view unmounts,
// not immediately after mounting or starting a download.

In React, create the address inside an effect and let that effect cleanup revoke exactly the address it created. Creating URLs as untracked render-time side effects makes abandoned renders difficult to clean up. Async output also needs task identity checks so a late result cannot reinstall an obsolete preview after cancellation.

Loaded does not always mean unused

An image load event is not necessarily the end of the address lifetime. A visible preview may still need right-click saving or opening in another tab, and other elements may share its address. One-shot decoding with no remaining consumers has a different retirement point from an interactive result. Video can also continue reading or seeking.

Downloads do not provide a universal completion callback

An anchor click starts an action; it is not a promise that the download has consumed the URL. Immediate revocation can race that consumption. A timeout is a heuristic rather than proof of completion. For a result page, retaining a usable download link until the result is retired also lets users retry. Test starting a download and switching results in the target browsers.

When a product needs explicit write completion, a supported, user-authorized file writing API can provide a close operation to await. That is a different compatibility and interaction choice from an ordinary download anchor. Do not silently turn an active download affordance into a broken address just to minimize a reference count.

Audit repeated use

  1. Track URL creation and revocation by result ID without logging sensitive Blob contents.
  2. Generate, replace and clear ten times; verify every retired result is revoked and active results are bounded.
  3. Exercise preview, download, context-menu save, cancellation and navigation to detect premature cleanup.
  4. Observe process-memory trends; investigate retained Blobs, bitmaps, canvases and Workers if usage still grows.

Frequently asked questions

Q.Is assigning null to the URL variable enough?

No. Dropping a string reference does not revoke the browser registration. The resource owner needs explicit cleanup.

Q.Does revoking delete a downloaded file?

No. It removes the temporary browser address. An operation that has not consumed that address may fail, but a saved file is unaffected.