Skip to content

Memory Management ​

This guide explains how TagLib-Wasm manages memory and best practices for optimal performance.

Memory Usage Patterns ​

Base Memory Requirements ​

  • Wasm Module: ~2-4MB (loaded once)
  • Per File: ~2x file size during processing
  • Peak Usage: ~3x file size during save operations

Memory Usage by Operation ​

OperationMemory UsageDuration
Loading file2x file sizeUntil disposed
Reading tagsNo additionalInstant
Writing tagsNo additionalInstant
Saving file3x file sizeDuring save()

Explicit Memory Management ​

TagLib-Wasm provides explicit memory management through the using keyword (via Symbol.dispose):

typescript
using audioFile = await taglib.open("song.mp3");
// Work with the file
const tags = audioFile.tag();
console.log(tags.title);
// Automatically disposed when audioFile goes out of scope

The dispose() method is also available as a fallback for environments that don't support using:

typescript
const audioFile = await taglib.open("song.mp3");
try {
  const tags = audioFile.tag();
  console.log(tags.title);
} finally {
  audioFile.dispose();
}

What Disposal Does ​

Disposal (whether via using or dispose()):

  1. Explicitly destroys the C++ object, freeing Wasm heap memory immediately
  2. Clears all JavaScript references
  3. Prevents memory accumulation in long-running applications

Best Practices ​

1. Always Use using Statements ​

typescript
{
  using audioFile = await taglib.open(buffer);
  // Your code here
} // Guaranteed cleanup when scope exits

2. Process Files Sequentially for Large Batches ​

typescript
// Good: Process one at a time
for (const file of files) {
  using audio = await taglib.open(file);
  await processFile(audio);
}

// Bad: Loading all at once
const audioFiles = await Promise.all(
  files.map((f) => taglib.open(f)),
); // Risk of memory exhaustion

3. Monitor Memory Usage ​

The Wasm heap is internal, so monitor at the runtime level instead:

typescript
// Node.js / Bun
const { heapUsed, rss } = process.memoryUsage();
console.log(`Heap: ${(heapUsed / 1024 / 1024).toFixed(1)}MB`);

// Deno: Deno.memoryUsage() returns the same shape

Memory Limits ​

  • WASI backend (Deno, Node.js, Bun): 16 MiB initial, 2 GiB maximum — the module declares these (--initial-memory=16777216, --max-memory=2147483648 in build/build-wasi.sh) and they are not settable at runtime
  • Emscripten backend (browsers, Web Workers, Cloudflare Workers, plain Node.js): memory growth enabled with a 4 GiB ceiling (-s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB in build/build-wasm.sh)
  • Cloudflare Workers: 128 MB per request, the platform's own cap
  • Recommended Max File Size: ~300MB
  • Concurrent Files: Depends on total size

Handling Large Files ​

For files larger than 100MB:

typescript
// Check file size before processing
const stats = await Deno.stat(filePath);
if (stats.size > 100 * 1024 * 1024) {
  console.warn(
    `Large file (${
      (stats.size / 1024 / 1024).toFixed(1)
    }MB), processing may be slow`,
  );
}

Common Memory Issues ​

1. Memory Accumulation ​

Problem: Not disposing files leads to memory accumulation.

Solution: Always use using statements or the Simple API which handles disposal automatically.

2. Out of Memory Errors ​

Problem: Processing too many large files concurrently.

Solution: Process files sequentially or in small batches.

3. Browser Memory Limits ​

Problem: Browsers have lower memory limits than Node.js.

Solution:

  • Use smaller batch sizes in browsers
  • Consider streaming approaches for very large files
  • Monitor memory usage and provide user feedback

Simple API Memory Management ​

The Simple API automatically handles memory management:

typescript
// Memory is automatically managed
const tags = await readTags("song.mp3");
console.log(tags.title?.[0]);

// No need to call dispose() - handled internally

Performance Tips ​

  1. Reuse TagLib Instance: The TagLib instance can be reused for multiple files
  2. Dispose Early: Use using to ensure files are disposed as soon as the scope exits
  3. Batch Wisely: Balance between memory usage and performance
  4. Monitor Production: Add memory monitoring in production applications

Example: Batch Processing with Memory Management ​

typescript
import { TagLib } from "taglib-wasm";

async function processMusicLibrary(files: string[]) {
  const taglib = await TagLib.initialize();
  const batchSize = 10;

  for (let i = 0; i < files.length; i += batchSize) {
    const batch = files.slice(i, i + batchSize);

    await Promise.all(batch.map(async (file) => {
      using audio = await taglib.open(file);
      const tags = audio.tag();
      console.log(`${file}: ${tags.artist} - ${tags.title}`);
    }));

    console.log(
      `Batch ${i / batchSize + 1} of ${
        Math.ceil(files.length / batchSize)
      } complete`,
    );
  }
}

Note: The Wasm heap is internal — there is no public API for inspecting it. Rely on using (or dispose()) per file, as above, to keep memory flat; the runtime reclaims Wasm memory as handles are disposed.

Released under the MIT License.