Fix #42839. avoid ui freeze when file is larger than heap size limit.
This commit is contained in:
parent
9f5a4a2102
commit
50a1deb9f6
23
src/main.js
23
src/main.js
|
@ -162,6 +162,21 @@ function touch(file) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveJSFlags() {
|
||||||
|
let jsFlags = [];
|
||||||
|
if (args['js-flags']) {
|
||||||
|
jsFlags.push(args['js-flag']);
|
||||||
|
}
|
||||||
|
if (args['max_old_space_size'] && !/max_old_space_size=(\d+)/g.exec(args['js-flags'])) {
|
||||||
|
jsFlags.push(`--max_old_space_size=${args['max_old_space_size']}`);
|
||||||
|
}
|
||||||
|
if (jsFlags.length > 0) {
|
||||||
|
return jsFlags.join(' ');
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Language tags are case insensitve however an amd loader is case sensitive
|
// Language tags are case insensitve however an amd loader is case sensitive
|
||||||
// To make this work on case preserving & insensitive FS we do the following:
|
// To make this work on case preserving & insensitive FS we do the following:
|
||||||
// the language bundles have lower case language tags and we always lower case
|
// the language bundles have lower case language tags and we always lower case
|
||||||
|
@ -441,7 +456,8 @@ let nodeCachedDataDir = getNodeCachedDataDir().then(function (value) {
|
||||||
|
|
||||||
// tell v8 to not be lazy when parsing JavaScript. Generally this makes startup slower
|
// tell v8 to not be lazy when parsing JavaScript. Generally this makes startup slower
|
||||||
// but because we generate cached data it makes subsequent startups much faster
|
// but because we generate cached data it makes subsequent startups much faster
|
||||||
app.commandLine.appendSwitch('--js-flags', '--nolazy');
|
let existingJSFlags = resolveJSFlags();
|
||||||
|
app.commandLine.appendSwitch('--js-flags', existingJSFlags ? existingJSFlags + ' --nolazy' : '--nolazy');
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
|
@ -454,6 +470,11 @@ userDefinedLocale.then((locale) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let jsFlags = resolveJSFlags();
|
||||||
|
if (jsFlags) {
|
||||||
|
app.commandLine.appendSwitch('--js-flags', jsFlags);
|
||||||
|
}
|
||||||
|
|
||||||
// Load our code once ready
|
// Load our code once ready
|
||||||
app.once('ready', function () {
|
app.once('ready', function () {
|
||||||
perf.mark('main:appReady');
|
perf.mark('main:appReady');
|
||||||
|
|
|
@ -306,6 +306,13 @@ export async function main(argv: string[]): TPromise<any> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args['js-flags']) {
|
||||||
|
const match = /max_old_space_size=(\d+)/g.exec(args['js-flags']);
|
||||||
|
if (match && !args['max_old_space_size']) {
|
||||||
|
argv.push(`--max_old_space_size=${match[1]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
detached: true,
|
detached: true,
|
||||||
env
|
env
|
||||||
|
|
|
@ -53,6 +53,7 @@ export interface ParsedArgs {
|
||||||
'disable-updates'?: string;
|
'disable-updates'?: string;
|
||||||
'disable-crash-reporter'?: string;
|
'disable-crash-reporter'?: string;
|
||||||
'skip-add-to-recently-opened'?: boolean;
|
'skip-add-to-recently-opened'?: boolean;
|
||||||
|
'max_old_space_size'?: number;
|
||||||
'file-write'?: boolean;
|
'file-write'?: boolean;
|
||||||
'file-chmod'?: boolean;
|
'file-chmod'?: boolean;
|
||||||
'upload-logs'?: string;
|
'upload-logs'?: string;
|
||||||
|
|
|
@ -167,6 +167,7 @@ const troubleshootingHelp: { [name: string]: string; } = {
|
||||||
'--inspect-brk-extensions': localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection uri."),
|
'--inspect-brk-extensions': localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection uri."),
|
||||||
'--disable-gpu': localize('disableGPU', "Disable GPU hardware acceleration."),
|
'--disable-gpu': localize('disableGPU', "Disable GPU hardware acceleration."),
|
||||||
'--upload-logs': localize('uploadLogs', "Uploads logs from current session to a secure endpoint."),
|
'--upload-logs': localize('uploadLogs', "Uploads logs from current session to a secure endpoint."),
|
||||||
|
'--max_old_space_size': localize('maxOldSpaceSize', "Max size of the old space (in Mbytes).")
|
||||||
};
|
};
|
||||||
|
|
||||||
export function formatOptions(options: { [name: string]: string; }, columns: number): string {
|
export function formatOptions(options: { [name: string]: string; }, columns: number): string {
|
||||||
|
|
|
@ -604,7 +604,8 @@ export enum FileOperationResult {
|
||||||
FILE_READ_ONLY,
|
FILE_READ_ONLY,
|
||||||
FILE_PERMISSION_DENIED,
|
FILE_PERMISSION_DENIED,
|
||||||
FILE_TOO_LARGE,
|
FILE_TOO_LARGE,
|
||||||
FILE_INVALID_PATH
|
FILE_INVALID_PATH,
|
||||||
|
FILE_EXCEED_HEAP
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AutoSaveConfiguration = {
|
export const AutoSaveConfiguration = {
|
||||||
|
|
|
@ -7,4 +7,9 @@
|
||||||
const WIN32_MAX_FILE_SIZE = 300 * 1024 * 1024; // 300 MB
|
const WIN32_MAX_FILE_SIZE = 300 * 1024 * 1024; // 300 MB
|
||||||
const GENERAL_MAX_FILE_SIZE = 16 * 1024 * 1024 * 1024; // 16 GB
|
const GENERAL_MAX_FILE_SIZE = 16 * 1024 * 1024 * 1024; // 16 GB
|
||||||
|
|
||||||
export const MAX_FILE_SIZE = process.arch === 'ia32' ? WIN32_MAX_FILE_SIZE : GENERAL_MAX_FILE_SIZE;
|
// See https://github.com/v8/v8/blob/5918a23a3d571b9625e5cce246bdd5b46ff7cd8b/src/heap/heap.cc#L149
|
||||||
|
const WIN32_MAX_HEAP_SIZE = 700 * 1024 * 1024; // 700 MB
|
||||||
|
const GENERAL_MAX_HEAP_SIZE = 700 * 2 * 1024 * 1024; // 1400 MB
|
||||||
|
|
||||||
|
export const MAX_FILE_SIZE = process.arch === 'ia32' ? WIN32_MAX_FILE_SIZE : GENERAL_MAX_FILE_SIZE;
|
||||||
|
export const MAX_HEAP_SIZE = process.arch === 'ia32' ? WIN32_MAX_HEAP_SIZE : GENERAL_MAX_HEAP_SIZE;
|
|
@ -84,7 +84,7 @@ export class FileService implements IFileService {
|
||||||
};
|
};
|
||||||
|
|
||||||
// create service
|
// create service
|
||||||
this.raw = new NodeFileService(contextService, textResourceConfigurationService, configurationService, lifecycleService, fileServiceConfig);
|
this.raw = new NodeFileService(contextService, environmentService, textResourceConfigurationService, configurationService, lifecycleService, fileServiceConfig);
|
||||||
|
|
||||||
// Listeners
|
// Listeners
|
||||||
this.registerListeners();
|
this.registerListeners();
|
||||||
|
|
|
@ -11,7 +11,7 @@ import os = require('os');
|
||||||
import crypto = require('crypto');
|
import crypto = require('crypto');
|
||||||
import assert = require('assert');
|
import assert = require('assert');
|
||||||
import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IFileStat, IStreamContent, FileOperationError, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, FileChangesEvent, ICreateFileOptions, IContentData, ITextSnapshot } from 'vs/platform/files/common/files';
|
import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IFileStat, IStreamContent, FileOperationError, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, FileChangesEvent, ICreateFileOptions, IContentData, ITextSnapshot } from 'vs/platform/files/common/files';
|
||||||
import { MAX_FILE_SIZE } from 'vs/platform/files/node/files';
|
import { MAX_FILE_SIZE, MAX_HEAP_SIZE } from 'vs/platform/files/node/files';
|
||||||
import { isEqualOrParent } from 'vs/base/common/paths';
|
import { isEqualOrParent } from 'vs/base/common/paths';
|
||||||
import { ResourceMap } from 'vs/base/common/map';
|
import { ResourceMap } from 'vs/base/common/map';
|
||||||
import arrays = require('vs/base/common/arrays');
|
import arrays = require('vs/base/common/arrays');
|
||||||
|
@ -36,6 +36,7 @@ import Event, { Emitter } from 'vs/base/common/event';
|
||||||
import { FileWatcher as NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/watcherService';
|
import { FileWatcher as NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/watcherService';
|
||||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
import { getBaseLabel } from 'vs/base/common/labels';
|
import { getBaseLabel } from 'vs/base/common/labels';
|
||||||
|
@ -131,6 +132,7 @@ export class FileService implements IFileService {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private contextService: IWorkspaceContextService,
|
private contextService: IWorkspaceContextService,
|
||||||
|
private environmentService: IEnvironmentService,
|
||||||
private textResourceConfigurationService: ITextResourceConfigurationService,
|
private textResourceConfigurationService: ITextResourceConfigurationService,
|
||||||
private configurationService: IConfigurationService,
|
private configurationService: IConfigurationService,
|
||||||
private lifecycleService: ILifecycleService,
|
private lifecycleService: ILifecycleService,
|
||||||
|
@ -316,12 +318,20 @@ export class FileService implements IFileService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return early if file is too large to load
|
// Return early if file is too large to load
|
||||||
if (typeof stat.size === 'number' && stat.size > MAX_FILE_SIZE) {
|
if (typeof stat.size === 'number') {
|
||||||
return onStatError(new FileOperationError(
|
if (stat.size > Math.max(this.environmentService.args['max_old_space_size'] * 1024 * 1024 || 0, MAX_HEAP_SIZE)) {
|
||||||
nls.localize('fileTooLargeError', "File too large to open"),
|
return onStatError(new FileOperationError(
|
||||||
FileOperationResult.FILE_TOO_LARGE,
|
nls.localize('fileTooLargeForHeapError', "File size exceeds V8 heap limit, please try to run code --max_old_space_size=NEWSIZE"),
|
||||||
options
|
FileOperationResult.FILE_EXCEED_HEAP
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat.size > MAX_FILE_SIZE) {
|
||||||
|
return onStatError(new FileOperationError(
|
||||||
|
nls.localize('fileTooLargeError', "File too large to open"),
|
||||||
|
FileOperationResult.FILE_TOO_LARGE
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return void 0;
|
return void 0;
|
||||||
|
@ -455,6 +465,13 @@ export class FileService implements IFileService {
|
||||||
currentPosition += bytesRead;
|
currentPosition += bytesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (totalBytesRead > Math.max(this.environmentService.args['max_old_space_size'] * 1024 * 1024 || 0, MAX_HEAP_SIZE)) {
|
||||||
|
finish(new FileOperationError(
|
||||||
|
nls.localize('fileTooLargeForHeapError', "File size exceeds V8 heap limit, please try to run code --max_old_space_size=NEWSIZE"),
|
||||||
|
FileOperationResult.FILE_EXCEED_HEAP
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if (totalBytesRead > MAX_FILE_SIZE) {
|
if (totalBytesRead > MAX_FILE_SIZE) {
|
||||||
// stop when reading too much
|
// stop when reading too much
|
||||||
finish(new FileOperationError(
|
finish(new FileOperationError(
|
||||||
|
|
Loading…
Reference in a new issue