diff --git a/package-lock.json b/package-lock.json index ae2ac741..4c76030b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -629,9 +629,9 @@ "dev": true }, "async": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz", - "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==" + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, "async-done": { "version": "1.3.2", diff --git a/package.json b/package.json index 42ebb990..908f8ce0 100644 --- a/package.json +++ b/package.json @@ -597,4 +597,4 @@ } ] } -} \ No newline at end of file +} diff --git a/src/client/clientErrorHandler.ts b/src/client/clientErrorHandler.ts index 0540a173..1c9fc4f6 100644 --- a/src/client/clientErrorHandler.ts +++ b/src/client/clientErrorHandler.ts @@ -1,10 +1,11 @@ import * as fs from "fs-extra"; -import { commands, ExtensionContext, window, workspace } from "vscode"; +import { commands, ConfigurationTarget, ExtensionContext, window, workspace } from "vscode"; import { CloseAction, ErrorAction, ErrorHandler, Message } from "vscode-languageclient"; import { ClientCommandConstants } from "../commands/commandConstants"; import { HEAP_DUMP_LOCATION } from "../server/java/jvmArguments"; import { Telemetry } from "../telemetry"; import glob = require("glob"); +import { totalmem } from "os"; /** * An error handler that restarts the language server, @@ -77,8 +78,9 @@ export async function cleanUpHeapDumps(context: ExtensionContext): Promise */ async function showOOMMessage(): Promise { const DOCS = 'More info...'; + const DOUBLE = 'Double allocated memory'; const result = await window.showErrorMessage('The XML Language Server crashed due to an Out Of Memory Error, and will not be restarted. ', // - DOCS); + DOUBLE, DOCS); if (result === DOCS) { Telemetry.sendTelemetry(Telemetry.OPEN_OOM_DOCS_EVT); await commands.executeCommand(ClientCommandConstants.OPEN_DOCS, @@ -87,10 +89,13 @@ async function showOOMMessage(): Promise { section: 'the-language-server-crashes-due-to-an-out-of-memory-error' } ); + } else if (result === DOUBLE) { + doubleAllocatedMemory(); } } const HEAP_DUMP_FOLDER_EXTRACTOR = new RegExp(`${HEAP_DUMP_LOCATION}(?:'([^']+)'|"([^"]+)"|([^\\s]+))`); +const MAX_HEAP_SIZE_EXTRACTOR = new RegExp(`-Xmx([0-9]+)[kKmMgG]`); /** * Returns the heap dump folder defined in the user's preferences, or undefined if the user does not set the heap dump folder @@ -122,4 +127,24 @@ function getXmxFromSettings(): string { } } return 'DEFAULT'; +} + +/** + * Double the memory allocated to lemminx in the vmargs parameter + */ +async function doubleAllocatedMemory() { + let vmargs: string = workspace.getConfiguration('xml.server').get('vmargs', null); + const results = MAX_HEAP_SIZE_EXTRACTOR.exec(vmargs); + if (results && results[0]) { + const maxMemArg: string = results[0]; + const maxMemValue: number = Number(results[1]); + const newMaxMemArg: string = maxMemArg.replace(maxMemValue.toString(), (maxMemValue * 2).toString()); + vmargs = vmargs.replace(maxMemArg, newMaxMemArg); + await workspace.getConfiguration().update("xml.server.vmargs", vmargs, ConfigurationTarget.Global); + } else { + // by default, many JVM take 1/4 of the physical memory as -Xmx + // in the case it crashes, set -Xmx to half of total physical memory, in megabytes + vmargs = `-Xmx ${Math.trunc(totalmem()/2/1000000)}m ${vmargs}`; + await workspace.getConfiguration().update("xml.server.vmargs", vmargs, ConfigurationTarget.Global); + } } \ No newline at end of file diff --git a/src/client/xmlClient.ts b/src/client/xmlClient.ts index bb2225fe..c3bf560b 100644 --- a/src/client/xmlClient.ts +++ b/src/client/xmlClient.ts @@ -1,5 +1,5 @@ import { TelemetryEvent } from '@redhat-developer/vscode-redhat-telemetry/lib'; -import { commands, ExtensionContext, extensions, Position, TextDocument, TextEditor, Uri, window, workspace } from 'vscode'; +import { commands, ConfigurationChangeEvent, ExtensionContext, extensions, Position, TextDocument, TextEditor, Uri, window, workspace } from 'vscode'; import { Command, ConfigurationParams, ConfigurationRequest, DidChangeConfigurationNotification, ExecuteCommandParams, LanguageClientOptions, MessageType, NotificationType, RequestType, RevealOutputChannelOn, TextDocumentPositionParams } from "vscode-languageclient"; import { Executable, LanguageClient } from 'vscode-languageclient/node'; import { XMLFileAssociation } from '../api/xmlExtensionApi'; diff --git a/src/settings/settings.ts b/src/settings/settings.ts index 9f68d4e0..d26ed887 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -52,6 +52,9 @@ export function subscribeJDKChangeConfiguration() { if(hasPreferenceChanged(oldXMLConfig, newXMLConfig, "java.home")) { // checks "xml.java.home", not "java.home" createReloadWindowMessage("`xml.java.home` path has changed. Please restart VS Code."); } + if (params.affectsConfiguration("xml.server.vmargs")) { + createReloadWindowMessage("Arguments to the JVM have changed. Please reload VS Code to apply this change."); + } // update to newest version of config oldXMLConfig = newXMLConfig; return;