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
JavaScript
/**
* メモリ最適化ユーティリティ
* 大容量データ処理時のメモリ効率を向上
*/
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