UNPKG

dnsweeper

Version:

Advanced CLI tool for DNS record risk analysis and cleanup. Features CSV import for Cloudflare/Route53, automated risk assessment, and parallel DNS validation.

198 lines 5.88 kB
/** * メモリ最適化ユーティリティ * 大容量データ処理時のメモリ効率を向上 */ export class MemoryOptimizer { static DEFAULT_WARNING_THRESHOLD = 512; // 512MB /** * 現在のメモリ使用量を取得 */ static getMemoryUsage() { const usage = process.memoryUsage(); return { used: Math.round(usage.heapUsed / 1024 / 1024), external: Math.round(usage.external / 1024 / 1024), heapUsed: Math.round(usage.heapUsed / 1024 / 1024), heapTotal: Math.round(usage.heapTotal / 1024 / 1024), rss: Math.round(usage.rss / 1024 / 1024), }; } /** * メモリ使用量をログ出力 */ static logMemoryUsage(label = 'Memory usage') { const usage = this.getMemoryUsage(); console.log(`${label}:`, { 'Heap Used': `${usage.heapUsed}MB`, 'Heap Total': `${usage.heapTotal}MB`, External: `${usage.external}MB`, RSS: `${usage.rss}MB`, }); } /** * メモリ警告チェック */ static checkMemoryWarning(threshold = this.DEFAULT_WARNING_THRESHOLD, onWarning) { const usage = this.getMemoryUsage(); if (usage.heapUsed > threshold) { onWarning?.(usage); return true; } return false; } /** * ガベージコレクション強制実行 */ static forceGarbageCollection() { if (global.gc) { global.gc(); } else { console.warn('Garbage collection is not exposed. Run with --expose-gc flag.'); } } /** * メモリ効率的な配列チャンク処理 */ static async processArrayInChunks(array, processor, chunkSize = 1000, onProgress) { const results = []; let processed = 0; for (let i = 0; i < array.length; i += chunkSize) { const chunk = array.slice(i, i + chunkSize); const chunkResults = await processor(chunk); results.push(...chunkResults); processed += chunk.length; onProgress?.(processed, array.length); // メモリ警告チェック this.checkMemoryWarning(512, (usage) => { console.warn(`Memory warning: ${usage.heapUsed}MB used`); this.forceGarbageCollection(); }); } return results; } /** * WeakMapベースのキャッシュ(メモリリーク防止) */ static createWeakCache() { return new WeakMap(); } /** * LRUキャッシュの実装 */ static createLRUCache(maxSize) { return new LRUCache(maxSize); } } /** * LRUキャッシュ実装 */ class LRUCache { cache = new Map(); maxSize; constructor(maxSize) { this.maxSize = maxSize; } get(key) { if (this.cache.has(key)) { // LRUのため再挿入 const value = this.cache.get(key); this.cache.delete(key); this.cache.set(key, value); return value; } return undefined; } set(key, value) { if (this.cache.has(key)) { this.cache.delete(key); } else if (this.cache.size >= this.maxSize) { // 最古のアイテムを削除 const firstKey = this.cache.keys().next().value; if (firstKey !== undefined) { this.cache.delete(firstKey); } } this.cache.set(key, value); } delete(key) { return this.cache.delete(key); } clear() { this.cache.clear(); } size() { return this.cache.size; } has(key) { return this.cache.has(key); } } /** * ストリーミング処理用のメモリ効率的なプロセッサー */ export class StreamProcessor { options; processedCount = 0; constructor(options = {}) { this.options = { chunkSize: 1000, highWaterMark: 64 * 1024, // 64KB objectMode: true, memoryWarningThreshold: 512, ...options, }; } /** * ストリーミング処理 */ async processStream(items, processor) { const results = []; let chunk = []; for await (const item of items) { chunk.push(item); if (chunk.length >= this.options.chunkSize) { const chunkResults = await this.processChunk(chunk, processor); results.push(...chunkResults); chunk = []; // チャンクをクリア // メモリチェック this.checkMemoryAndCleanup(); } } // 残りのアイテムを処理 if (chunk.length > 0) { const chunkResults = await this.processChunk(chunk, processor); results.push(...chunkResults); } return results; } async processChunk(chunk, processor) { const results = []; for (const item of chunk) { try { const result = await processor(item); results.push(result); this.processedCount++; } catch (error) { console.error('Error processing item:', error); } } return results; } checkMemoryAndCleanup() { const threshold = this.options.memoryWarningThreshold || 512; MemoryOptimizer.checkMemoryWarning(threshold, (usage) => { this.options.onMemoryWarning?.(usage); MemoryOptimizer.forceGarbageCollection(); }); } getProcessedCount() { return this.processedCount; } reset() { this.processedCount = 0; } } //# sourceMappingURL=memory-optimizer.js.map