Version: EdgeVec v0.7.0 Last Updated: 2025-12-29
EdgeVec provides a comprehensive memory pressure monitoring and management API for WASM environments where memory is limited.
In browser environments, WASM modules have limited memory (typically 1-4GB max). The Memory Management API helps you:
- Monitor current memory usage
- Detect when memory pressure becomes critical
- Control insert behavior based on available memory
- Optimize memory usage through compaction
Get current memory usage and pressure level.
getMemoryPressure(): MemoryPressureReturns:
interface MemoryPressure {
level: 'normal' | 'warning' | 'critical';
usedBytes: number;
totalBytes: number;
usagePercent: number;
}Pressure Levels:
| Level | Threshold | Meaning |
|---|---|---|
normal |
<70% | Safe to insert |
warning |
70-90% | Consider compaction |
critical |
>90% | Inserts may be blocked |
Example:
const pressure = index.getMemoryPressure();
console.log(`Memory: ${pressure.usedBytes} / ${pressure.totalBytes}`);
console.log(`Usage: ${pressure.usagePercent.toFixed(1)}%`);
console.log(`Level: ${pressure.level}`);
// Example output:
// Memory: 52428800 / 268435456
// Usage: 19.5%
// Level: normalCheck if inserts are allowed based on memory pressure.
canInsert(): booleanReturns: false when memory is at critical level (>90% by default).
Example:
function safeInsert(vector: Float32Array, metadata: object): number | null {
if (!index.canInsert()) {
console.warn('Memory pressure critical, cannot insert');
return null;
}
return index.insertWithMetadata(vector, metadata);
}Configure memory pressure thresholds and behavior.
setMemoryConfig(config: MemoryConfig): voidParameters:
interface MemoryConfig {
warningThreshold?: number; // Default: 0.70 (70%)
criticalThreshold?: number; // Default: 0.90 (90%)
blockInsertsAtCritical?: boolean; // Default: true
}Example:
// More aggressive thresholds for low-memory devices
index.setMemoryConfig({
warningThreshold: 0.50, // Warn at 50%
criticalThreshold: 0.75, // Critical at 75%
blockInsertsAtCritical: true
});
// Allow inserts even at critical (use with caution!)
index.setMemoryConfig({
blockInsertsAtCritical: false
});Get actionable guidance based on current memory state.
getMemoryRecommendation(): stringReturns: Human-readable suggestion.
Example Outputs:
| State | Recommendation |
|---|---|
| Normal, no tombstones | "Memory usage is healthy." |
| Normal, some tombstones | "Consider running compact() to reclaim 15% memory." |
| Warning | "Memory pressure elevated. Run compact() or reduce vector count." |
| Critical | "Memory critical. Immediate action required: compact() or delete vectors." |
Example:
const recommendation = index.getMemoryRecommendation();
console.log(recommendation);
if (recommendation.includes('compact')) {
const result = index.compact();
console.log(`Compaction freed ${result.tombstones_removed} vectors`);
}The most effective way to reduce memory: 32x reduction.
// BQ is auto-enabled for dimensions divisible by 8
const index = new EdgeVec({ dimensions: 768 });
// Memory comparison (100k vectors, 768D):
// - F32: ~300 MB
// - BQ: ~10 MBRemove deleted vectors to reclaim memory.
// Check if compaction would help
if (index.needsCompaction()) {
const before = index.getMemoryPressure();
const result = index.compact();
const after = index.getMemoryPressure();
console.log(`Freed ${result.tombstones_removed} tombstones`);
console.log(`Memory: ${before.usagePercent}% -> ${after.usagePercent}%`);
}function autoCompact(index: EdgeVec): void {
const pressure = index.getMemoryPressure();
const ratio = index.tombstoneRatio();
// Compact if:
// 1. Memory pressure is warning+ AND tombstone ratio > 10%
// 2. Tombstone ratio exceeds 30% regardless of pressure
if ((pressure.level !== 'normal' && ratio > 0.1) || ratio > 0.3) {
console.log('Auto-compacting...');
index.compact();
}
}
// Call periodically or after batch deletions
autoCompact(index);async function insertWithMemoryCheck(
index: EdgeVec,
vectors: Float32Array[],
onMemoryWarning: () => void
): Promise<number[]> {
const ids: number[] = [];
for (const vector of vectors) {
// Check before each insert
if (!index.canInsert()) {
// Try compaction first
if (index.needsCompaction()) {
index.compact();
}
// Still can't insert?
if (!index.canInsert()) {
onMemoryWarning();
break;
}
}
ids.push(index.insert(vector));
}
return ids;
}| Component | F32 Mode | BQ Mode |
|---|---|---|
| Vector data | 4 * dim bytes | dim/8 bytes |
| HNSW node | ~64 bytes | ~64 bytes |
| Metadata (avg) | ~100 bytes | ~100 bytes |
Examples (768D):
| Mode | Per Vector | 100k Vectors | 1M Vectors |
|---|---|---|---|
| F32 only | ~3.2 KB | ~320 MB | ~3.2 GB |
| F32 + BQ | ~3.3 KB | ~330 MB | ~3.3 GB |
| BQ only | ~260 bytes | ~26 MB | ~260 MB |
function estimateCapacity(
dimensions: number,
useBQ: boolean,
maxMemoryMB: number
): number {
const perVectorBytes = useBQ
? (dimensions / 8) + 64 + 100 // BQ + node + metadata
: (dimensions * 4) + 64 + 100; // F32 + node + metadata
const maxBytes = maxMemoryMB * 1024 * 1024;
const overhead = 0.2; // 20% overhead for WASM heap management
return Math.floor(maxBytes * (1 - overhead) / perVectorBytes);
}
// Examples:
console.log('F32 capacity (768D, 1GB):', estimateCapacity(768, false, 1024));
// ~312,500 vectors
console.log('BQ capacity (768D, 1GB):', estimateCapacity(768, true, 1024));
// ~3,355,443 vectorsfunction createMemoryDashboard(index: EdgeVec): object {
const pressure = index.getMemoryPressure();
const stats = {
vectorCount: index.vectorCount(),
liveCount: index.liveCount(),
deletedCount: index.deletedCount(),
tombstoneRatio: (index.tombstoneRatio() * 100).toFixed(1) + '%'
};
return {
memory: {
used: formatBytes(pressure.usedBytes),
total: formatBytes(pressure.totalBytes),
percent: pressure.usagePercent.toFixed(1) + '%',
level: pressure.level
},
vectors: stats,
recommendation: index.getMemoryRecommendation(),
canInsert: index.canInsert(),
needsCompaction: index.needsCompaction(),
hasBQ: index.hasBQ()
};
}
function formatBytes(bytes: number): string {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
return (bytes / (1024 * 1024 * 1024)).toFixed(1) + ' GB';
}
// Usage
const dashboard = createMemoryDashboard(index);
console.log(JSON.stringify(dashboard, null, 2));- Monitor regularly - Check memory pressure before bulk operations
- Compact proactively - Don't wait for critical pressure
- Use BQ when possible - 32x memory savings with minimal recall loss
- Set appropriate thresholds - Lower on mobile, higher on desktop
- Handle insert blocks gracefully - Provide user feedback
try {
if (!index.canInsert()) {
throw new Error('Memory pressure too high');
}
index.insert(vector);
} catch (e) {
if (e.message.includes('memory')) {
// Memory-related error
console.warn('Memory issue:', e.message);
// Try to recover
if (index.needsCompaction()) {
index.compact();
}
} else {
throw e;
}
}- WASM_INDEX.md - Complete EdgeVec API
- Binary Quantization Guide
- Performance Tuning