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
|
||||
// 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
|
||||
|
@ -441,7 +456,8 @@ let nodeCachedDataDir = getNodeCachedDataDir().then(function (value) {
|
|||
|
||||
// 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
|
||||
app.commandLine.appendSwitch('--js-flags', '--nolazy');
|
||||
let existingJSFlags = resolveJSFlags();
|
||||
app.commandLine.appendSwitch('--js-flags', existingJSFlags ? existingJSFlags + ' --nolazy' : '--nolazy');
|
||||
}
|
||||
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
|
||||
app.once('ready', function () {
|
||||
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 = {
|
||||
detached: true,
|
||||
env
|
||||
|
|
|
@ -53,6 +53,7 @@ export interface ParsedArgs {
|
|||
'disable-updates'?: string;
|
||||
'disable-crash-reporter'?: string;
|
||||
'skip-add-to-recently-opened'?: boolean;
|
||||
'max_old_space_size'?: number;
|
||||
'file-write'?: boolean;
|
||||
'file-chmod'?: boolean;
|
||||
'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."),
|
||||
'--disable-gpu': localize('disableGPU', "Disable GPU hardware acceleration."),
|
||||
'--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 {
|
||||
|
|
|
@ -604,7 +604,8 @@ export enum FileOperationResult {
|
|||
FILE_READ_ONLY,
|
||||
FILE_PERMISSION_DENIED,
|
||||
FILE_TOO_LARGE,
|
||||
FILE_INVALID_PATH
|
||||
FILE_INVALID_PATH,
|
||||
FILE_EXCEED_HEAP
|
||||
}
|
||||
|
||||
export const AutoSaveConfiguration = {
|
||||
|
|
|
@ -7,4 +7,9 @@
|
|||
const WIN32_MAX_FILE_SIZE = 300 * 1024 * 1024; // 300 MB
|
||||
const GENERAL_MAX_FILE_SIZE = 16 * 1024 * 1024 * 1024; // 16 GB
|
||||
|
||||
// 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
|
||||
this.raw = new NodeFileService(contextService, textResourceConfigurationService, configurationService, lifecycleService, fileServiceConfig);
|
||||
this.raw = new NodeFileService(contextService, environmentService, textResourceConfigurationService, configurationService, lifecycleService, fileServiceConfig);
|
||||
|
||||
// Listeners
|
||||
this.registerListeners();
|
||||
|
|
|
@ -11,7 +11,7 @@ import os = require('os');
|
|||
import crypto = require('crypto');
|
||||
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 { 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 { ResourceMap } from 'vs/base/common/map';
|
||||
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 { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
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 { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { getBaseLabel } from 'vs/base/common/labels';
|
||||
|
@ -131,6 +132,7 @@ export class FileService implements IFileService {
|
|||
|
||||
constructor(
|
||||
private contextService: IWorkspaceContextService,
|
||||
private environmentService: IEnvironmentService,
|
||||
private textResourceConfigurationService: ITextResourceConfigurationService,
|
||||
private configurationService: IConfigurationService,
|
||||
private lifecycleService: ILifecycleService,
|
||||
|
@ -316,13 +318,21 @@ export class FileService implements IFileService {
|
|||
}
|
||||
|
||||
// Return early if file is too large to load
|
||||
if (typeof stat.size === 'number' && stat.size > MAX_FILE_SIZE) {
|
||||
if (typeof stat.size === 'number') {
|
||||
if (stat.size > Math.max(this.environmentService.args['max_old_space_size'] * 1024 * 1024 || 0, MAX_HEAP_SIZE)) {
|
||||
return onStatError(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 (stat.size > MAX_FILE_SIZE) {
|
||||
return onStatError(new FileOperationError(
|
||||
nls.localize('fileTooLargeError', "File too large to open"),
|
||||
FileOperationResult.FILE_TOO_LARGE,
|
||||
options
|
||||
FileOperationResult.FILE_TOO_LARGE
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return void 0;
|
||||
}, err => {
|
||||
|
@ -455,6 +465,13 @@ export class FileService implements IFileService {
|
|||
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) {
|
||||
// stop when reading too much
|
||||
finish(new FileOperationError(
|
||||
|
|
Loading…
Reference in a new issue