Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Cleanup old file/folder watch callbacks #3536

Open
Labels
blocked by another issueIssues which are not ready because another issue needs to be resolved firstbugSomething isn't workingpackage: typescript-estreeIssues related to @typescript-eslint/typescript-estreeperformanceIssues regarding performance
@bradzacher

Description

@bradzacher

As part of supporting IDE runs we use TS "watch programs" to allow efficient recomputation of the TS program as the IDE sends us updated code for files.

However, as we also need to simultaneously support CLI runs we cannot allow TS to actually attach file watchers to the filesystem. File watchers count as open pipes - which will cause NodeJS to prevent ESLint from ever exiting (making it seem like ESLint has "hung").

So in order for us to "get the best of both worlds", we take the callback functions that TS uses to be alerted of filesystem changes and we store them in a map of sets (keyed by the file path).

/**
* Maps file/folder paths to their set of corresponding watch callbacks
* There may be more than one per file/folder if a file/folder is shared between projects
*/
constfileWatchCallbackTrackingMap=newMap<
CanonicalPath,
Set<ts.FileWatcherCallback>
>();
constfolderWatchCallbackTrackingMap=newMap<
CanonicalPath,
Set<ts.FileWatcherCallback>
>();

watchCompilerHost.watchFile=saveWatchCallback(fileWatchCallbackTrackingMap);
watchCompilerHost.watchDirectory=saveWatchCallback(
folderWatchCallbackTrackingMap,
);

functionsaveWatchCallback(
trackingMap:Map<string,Set<ts.FileWatcherCallback>>,
){
return(
fileName:string,
callback:ts.FileWatcherCallback,
):ts.FileWatcher=>{
constnormalizedFileName=getCanonicalFileName(fileName);
constwatchers=(():Set<ts.FileWatcherCallback>=>{
letwatchers=trackingMap.get(normalizedFileName);
if(!watchers){
watchers=newSet();
trackingMap.set(normalizedFileName,watchers);
}
returnwatchers;
})();
watchers.add(callback);
return{
close:():void=>{
watchers.delete(callback);
},
};
};
}

Looking at TS's source code...

It has one place where it passes in a constant function pointer in towatchFile:

And many places where it passes arrow functions in towatchFile/watchDirectory:

As we (and the TS program) do not have any "cleanup" step - it means we never clear these caches. We do not know when or if we can remove functions from these caches. This means we can accumulate these callbacks indefinitely.

They're just itty bitty function references - what's the problem?!? The issue is that functions have a closure which stores variables. In some of these cases the closure contains a reference to aSourceFile. Which means that Node cannot GC theSourceFile (or anything else in the closure for that matter) unless we free our function reference.

This is a problem asSourceFiles aren't the lightest data structure - so unbounded accumulation of them can cause an OOM. An extreme example of this is#3533 - wherein they had a bad config file, meaning we would throw away and recreate the watch host for each file without cleaning up its watch functions.

I don't know if this actually impacts "good" project setups - but we should really profile this and figure out what sort of memory usage this causes for different usecases (big project, small project, many projects). I don't have a good solution for this either. We can't useWeakRef because we are the sole owner of the function reference.. so we would need another mechanism to clean up.

cc@uniqueiniquity for the TS side of things

Metadata

Metadata

Assignees

No one assigned

    Labels

    blocked by another issueIssues which are not ready because another issue needs to be resolved firstbugSomething isn't workingpackage: typescript-estreeIssues related to @typescript-eslint/typescript-estreeperformanceIssues regarding performance

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2025 Movatter.jp