Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reduce memory usage and fix memory leaks #13580

Merged
merged 3 commits into from Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 43 additions & 28 deletions lib/Compilation.js
Expand Up @@ -337,6 +337,31 @@ const deprecatedNormalModuleLoaderHook = util.deprecate(
"DEP_WEBPACK_COMPILATION_NORMAL_MODULE_LOADER_HOOK"
);

// TODO webpack 6: remove
const defineRemovedModuleTemplates = moduleTemplates => {
Object.defineProperties(moduleTemplates, {
asset: {
enumerable: false,
configurable: false,
get: () => {
throw new WebpackError(
"Compilation.moduleTemplates.asset has been removed"
);
}
},
webassembly: {
enumerable: false,
configurable: false,
get: () => {
throw new WebpackError(
"Compilation.moduleTemplates.webassembly has been removed"
);
}
}
});
moduleTemplates = undefined;
};

const byId = compareSelect(
/**
* @param {Chunk} c chunk
Expand Down Expand Up @@ -861,26 +886,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
this.moduleTemplates = {
javascript: new ModuleTemplate(this.runtimeTemplate, this)
};
Object.defineProperties(this.moduleTemplates, {
asset: {
enumerable: false,
configurable: false,
get() {
throw new WebpackError(
"Compilation.moduleTemplates.asset has been removed"
);
}
},
webassembly: {
enumerable: false,
configurable: false,
get() {
throw new WebpackError(
"Compilation.moduleTemplates.webassembly has been removed"
);
}
}
});
defineRemovedModuleTemplates(this.moduleTemplates);

this.moduleGraph = new ModuleGraph();
/** @type {ChunkGraph} */
Expand Down Expand Up @@ -1999,6 +2005,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
}

finish(callback) {
this.factorizeQueue.clear();
if (this.profile) {
this.logger.time("finish module profiles");
const ParallelismFactorCalculator = require("./util/ParallelismFactorCalculator");
Expand Down Expand Up @@ -2233,6 +2240,14 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
* @returns {void}
*/
seal(callback) {
const finalCallback = err => {
this.factorizeQueue.clear();
this.buildQueue.clear();
this.rebuildQueue.clear();
this.processDependenciesQueue.clear();
this.addModuleQueue.clear();
return callback(err);
};
const chunkGraph = new ChunkGraph(this.moduleGraph);
this.chunkGraph = chunkGraph;

Expand Down Expand Up @@ -2397,7 +2412,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o

this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => {
if (err) {
return callback(
return finalCallback(
makeWebpackError(err, "Compilation.hooks.optimizeTree")
);
}
Expand All @@ -2409,7 +2424,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
this.modules,
err => {
if (err) {
return callback(
return finalCallback(
makeWebpackError(err, "Compilation.hooks.optimizeChunkModules")
);
}
Expand Down Expand Up @@ -2452,7 +2467,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
this.hooks.beforeCodeGeneration.call();
this.codeGeneration(err => {
if (err) {
return callback(err);
return finalCallback(err);
}
this.hooks.afterCodeGeneration.call();
this.logger.timeEnd("code generation");
Expand All @@ -2471,7 +2486,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o

this._runCodeGenerationJobs(codeGenerationJobs, err => {
if (err) {
return callback(err);
return finalCallback(err);
}

if (shouldRecord) {
Expand All @@ -2491,7 +2506,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
this.logger.time("process assets");
this.hooks.processAssets.callAsync(this.assets, err => {
if (err) {
return callback(
return finalCallback(
makeWebpackError(err, "Compilation.hooks.processAssets")
);
}
Expand All @@ -2517,12 +2532,12 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
}
return this.hooks.afterSeal.callAsync(err => {
if (err) {
return callback(
return finalCallback(
makeWebpackError(err, "Compilation.hooks.afterSeal")
);
}
this.fileSystemInfo.logStatistics();
callback();
finalCallback();
});
});
};
Expand All @@ -2533,7 +2548,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
this.createChunkAssets(err => {
this.logger.timeEnd("create chunk assets");
if (err) {
return callback(err);
return finalCallback(err);
}
cont();
});
Expand Down
3 changes: 3 additions & 0 deletions lib/cache/PackFileCacheStrategy.js
Expand Up @@ -8,6 +8,7 @@
const FileSystemInfo = require("../FileSystemInfo");
const ProgressPlugin = require("../ProgressPlugin");
const { formatSize } = require("../SizeFormatHelpers");
const SerializerMiddleware = require("../serialization/SerializerMiddleware");
const LazySet = require("../util/LazySet");
const makeSerializable = require("../util/makeSerializable");
const memoize = require("../util/memoize");
Expand Down Expand Up @@ -715,6 +716,7 @@ class PackContent {
this.logger.timeEnd(timeMessage);
}
this.content = map;
this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
return map.get(identifier);
});
} else {
Expand All @@ -723,6 +725,7 @@ class PackContent {
this.logger.timeEnd(timeMessage);
}
this.content = map;
this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
return map.get(identifier);
}
}
Expand Down
19 changes: 19 additions & 0 deletions lib/serialization/SerializerMiddleware.js
Expand Up @@ -126,6 +126,25 @@ class SerializerMiddleware {
fn[LAZY_SERIALIZED_VALUE] = lazy;
return fn;
}

/**
* @param {function(): Promise<any> | any} lazy lazy function
* @returns {function(): Promise<any> | any} new lazy
*/
static unMemoizeLazy(lazy) {
if (!SerializerMiddleware.isLazy(lazy)) return lazy;
const fn = () => {
throw new Error(
"A lazy value that has been unmemorized can't be called again"
);
};
fn[LAZY_SERIALIZED_VALUE] = SerializerMiddleware.unMemoizeLazy(
lazy[LAZY_SERIALIZED_VALUE]
);
fn[LAZY_TARGET] = lazy[LAZY_TARGET];
fn.options = /** @type {any} */ (lazy).options;
return fn;
}
}

module.exports = SerializerMiddleware;
8 changes: 8 additions & 0 deletions lib/util/ArrayQueue.js
Expand Up @@ -27,6 +27,14 @@ class ArrayQueue {
return this._list.length + this._listReversed.length;
}

/**
* Empties the queue.
*/
clear() {
this._list.length = 0;
this._listReversed.length = 0;
}

/**
* Appends the specified element to this queue.
* @param {T} item The element to add.
Expand Down
9 changes: 9 additions & 0 deletions lib/util/AsyncQueue.js
Expand Up @@ -359,6 +359,15 @@ class AsyncQueue {
inHandleResult--;
});
}

clear() {
this._entries.clear();
this._queued.clear();
this._activeTasks = 0;
this._willEnsureProcessing = false;
this._needProcessing = false;
this._stopped = false;
}
}

module.exports = AsyncQueue;
1 change: 1 addition & 0 deletions types.d.ts
Expand Up @@ -358,6 +358,7 @@ declare abstract class AsyncQueue<T, K, R> {
isProcessing(item: T): boolean;
isQueued(item: T): boolean;
isDone(item: T): boolean;
clear(): void;
}
declare class AsyncWebAssemblyModulesPlugin {
constructor(options?: any);
Expand Down