Skip to content

Commit 6f563b7

Browse files
Fixed memory leak from '--watch' flag.
As I initially feared, we were actually nesting closure environments with each new `getSourceFile`. Fixes #366.
1 parent afeabe8 commit 6f563b7

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

src/compiler/core.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ module ts {
156156
return result;
157157
}
158158

159+
export function arrayToMap<T>(array: T[], f: (value: T) => string): Map<T> {
160+
var result: Map<T> = {};
161+
162+
forEach(array, value => { result[f(value)] = value });
163+
164+
return result;
165+
}
166+
159167
function formatStringFromArgs(text: string, args: { [index: number]: any; }, baseIndex?: number): string {
160168
baseIndex = baseIndex || 0;
161169

src/compiler/tc.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,14 @@ module ts {
238238

239239
function addWatchers(program: Program) {
240240
forEach(program.getSourceFiles(), f => {
241-
var filename = f.filename;
241+
var filename = getCanonicalName(f.filename);
242242
watchers[filename] = sys.watchFile(filename, fileUpdated);
243243
});
244244
}
245245

246246
function removeWatchers(program: Program) {
247247
forEach(program.getSourceFiles(), f => {
248-
var filename = f.filename;
248+
var filename = getCanonicalName(f.filename);
249249
if (hasProperty(watchers, filename)) {
250250
watchers[filename].close();
251251
}
@@ -257,8 +257,7 @@ module ts {
257257
// Fired off whenever a file is changed.
258258
function fileUpdated(filename: string) {
259259
var firstNotification = isEmpty(updatedFiles);
260-
261-
updatedFiles[filename] = true;
260+
updatedFiles[getCanonicalName(filename)] = true;
262261

263262
// Only start this off when the first file change comes in,
264263
// so that we can batch up all further changes.
@@ -279,16 +278,21 @@ module ts {
279278
removeWatchers(program);
280279

281280
// Gets us syntactically correct files from the last compilation.
282-
var getUnmodifiedSourceFile = program.getSourceFile;
281+
var oldSourceFiles = arrayToMap(program.getSourceFiles(), file => getCanonicalName(file.filename));
282+
283+
// No longer using the old program.
284+
program = undefined;
283285

284286
// We create a new compiler host for this compilation cycle.
285287
// This new host is effectively the same except that 'getSourceFile'
286288
// will try to reuse the SourceFiles from the last compilation cycle
287289
// so long as they were not modified.
288290
var newCompilerHost = clone(compilerHost);
289291
newCompilerHost.getSourceFile = (fileName, languageVersion, onError) => {
292+
fileName = getCanonicalName(fileName);
293+
290294
if (!hasProperty(changedFiles, fileName)) {
291-
var sourceFile = getUnmodifiedSourceFile(fileName);
295+
var sourceFile = lookUp(oldSourceFiles, fileName);
292296
if (sourceFile) {
293297
return sourceFile;
294298
}
@@ -301,6 +305,10 @@ module ts {
301305
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes));
302306
addWatchers(program);
303307
}
308+
309+
function getCanonicalName(fileName: string) {
310+
return compilerHost.getCanonicalFileName(fileName);
311+
}
304312
}
305313

306314
function compile(commandLine: ParsedCommandLine, compilerHost: CompilerHost) {

0 commit comments

Comments
 (0)