analyze-memory.mjs•6.48 kB
import v8 from 'v8';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// Create directory for snapshots
const snapshotDir = path.join(__dirname, 'heap-snapshots');
if (!fs.existsSync(snapshotDir)) {
fs.mkdirSync(snapshotDir, { recursive: true });
}
// Clean old snapshots
fs.readdirSync(snapshotDir).forEach(file => {
if (file.endsWith('.heapsnapshot')) {
fs.unlinkSync(path.join(snapshotDir, file));
}
});
function formatBytes(bytes) {
return (bytes / 1024 / 1024).toFixed(2) + ' MB';
}
function logMemory(label) {
if (global.gc) global.gc();
const mem = process.memoryUsage();
console.log(`[${label}]`);
console.log(` Heap Used: ${formatBytes(mem.heapUsed)}`);
console.log(` Heap Total: ${formatBytes(mem.heapTotal)}`);
console.log(` RSS: ${formatBytes(mem.rss)}`);
console.log(` External: ${formatBytes(mem.external)}`);
}
function takeSnapshot(label) {
const filename = path.join(snapshotDir, `${label}.heapsnapshot`);
v8.writeHeapSnapshot(filename);
console.log(` → Snapshot saved: ${label}.heapsnapshot`);
}
console.log('=== Memory Analysis for TypeScript Language Server ===\n');
// Initial state
logMemory('Initial');
takeSnapshot('01-initial');
// Test 1: Just import TypeScript
console.log('\n--- Importing TypeScript ---');
const before1 = process.memoryUsage().heapUsed;
const ts = await import('typescript');
const after1 = process.memoryUsage().heapUsed;
console.log(`TypeScript import added: ${formatBytes(after1 - before1)}`);
logMemory('After TypeScript import');
takeSnapshot('02-after-typescript');
// Test 2: Import our modules (which depend on TypeScript)
console.log('\n--- Importing Language Server modules ---');
const before2 = process.memoryUsage().heapUsed;
const { LanguageServerManager } = await import('./dist/languageServerManager.js');
const { LanguageServerService } = await import('./dist/languageServerService.js');
const after2 = process.memoryUsage().heapUsed;
console.log(`Language Server modules added: ${formatBytes(after2 - before2)}`);
logMemory('After Language Server import');
takeSnapshot('03-after-langserver');
// Test 3: Create instances
console.log('\n--- Creating Language Server instances ---');
const before3 = process.memoryUsage().heapUsed;
const manager = new LanguageServerManager({
monorepoRoot: '/test/monorepo',
projects: []
});
const service = new LanguageServerService();
const after3 = process.memoryUsage().heapUsed;
console.log(`Instances creation added: ${formatBytes(after3 - before3)}`);
logMemory('After instance creation');
takeSnapshot('04-after-instances');
// Test 4: Parse a simple TypeScript config
console.log('\n--- Parsing TypeScript config ---');
const before4 = process.memoryUsage().heapUsed;
const configText = JSON.stringify({
compilerOptions: {
target: 'es2020',
module: 'commonjs',
skipLibCheck: true,
noLib: true,
types: [],
},
exclude: ['node_modules']
});
const parseResult = ts.default.parseConfigFileTextToJson('tsconfig.json', configText);
const parsedConfig = ts.default.parseJsonConfigFileContent(
parseResult.config,
ts.default.sys,
'/test/project',
undefined,
'tsconfig.json'
);
const after4 = process.memoryUsage().heapUsed;
console.log(`Config parsing added: ${formatBytes(after4 - before4)}`);
console.log(`Found ${parsedConfig.fileNames.length} files`);
logMemory('After config parsing');
takeSnapshot('05-after-config');
// Test 5: Create a language service
console.log('\n--- Creating TypeScript Language Service ---');
const before5 = process.memoryUsage().heapUsed;
const files = new Map();
const host = {
getScriptFileNames: () => ['test.ts'],
getScriptVersion: () => '1',
getScriptSnapshot: (fileName) => {
if (fileName === 'test.ts') {
return ts.default.ScriptSnapshot.fromString('const x: number = 1;');
}
return undefined;
},
getCurrentDirectory: () => '/test',
getCompilationSettings: () => ({
target: ts.default.ScriptTarget.ES2020,
module: ts.default.ModuleKind.CommonJS,
skipLibCheck: true,
noLib: true,
types: [],
}),
getDefaultLibFileName: (options) => ts.default.getDefaultLibFilePath(options),
fileExists: () => false,
readFile: () => undefined,
readDirectory: () => [],
directoryExists: () => false,
getDirectories: () => [],
};
const languageService = ts.default.createLanguageService(host);
const after5 = process.memoryUsage().heapUsed;
console.log(`Language Service creation added: ${formatBytes(after5 - before5)}`);
logMemory('After Language Service');
takeSnapshot('06-after-langservice');
// Test 6: Get diagnostics (this might load type definitions)
console.log('\n--- Getting diagnostics ---');
const before6 = process.memoryUsage().heapUsed;
try {
const diagnostics = languageService.getSemanticDiagnostics('test.ts');
console.log(`Found ${diagnostics.length} diagnostics`);
} catch (e) {
console.log('Diagnostics failed:', e.message);
}
const after6 = process.memoryUsage().heapUsed;
console.log(`Diagnostics added: ${formatBytes(after6 - before6)}`);
logMemory('After diagnostics');
takeSnapshot('07-after-diagnostics');
// Summary
console.log('\n=== Memory Growth Summary ===');
const initialMem = process.memoryUsage().heapUsed;
console.log(`Total heap growth: ${formatBytes(initialMem - before1)}`);
console.log(` TypeScript import: ${formatBytes(after1 - before1)}`);
console.log(` Language Server modules: ${formatBytes(after2 - before2)}`);
console.log(` Instance creation: ${formatBytes(after3 - before3)}`);
console.log(` Config parsing: ${formatBytes(after4 - before4)}`);
console.log(` Language Service: ${formatBytes(after5 - before5)}`);
console.log(` Diagnostics: ${formatBytes(after6 - before6)}`);
console.log('\n=== Heap Snapshots ===');
console.log(`Saved to: ${snapshotDir}`);
console.log('\nTo analyze:');
console.log('1. Open Chrome DevTools (chrome://inspect)');
console.log('2. Go to Memory tab');
console.log('3. Load and compare the snapshots');
// Let's also check what TypeScript modules are loaded
console.log('\n=== Loaded TypeScript Modules ===');
const tsModules = Object.keys(require.cache).filter(m => m.includes('typescript'));
console.log(`Found ${tsModules.length} TypeScript-related modules loaded`);