1- import { window } from "vscode" ;
1+ import * as fs from "fs-extra" ;
2+ import { commands , ExtensionContext , window , workspace } from "vscode" ;
23import { CloseAction , ErrorAction , ErrorHandler , Message } from "vscode-languageclient" ;
4+ import { ClientCommandConstants } from "../commands/commandConstants" ;
5+ import { HEAP_DUMP_LOCATION } from "../server/java/jvmArguments" ;
6+ import glob = require( "glob" ) ;
37
48/**
59 * An error handler that restarts the language server,
6- * unless it has been restarted 5 times in the last 3 minutes
10+ * unless it has been restarted 5 times in the last 3 minutes,
11+ * or if it crashed due to an Out Of Memory Error
712 *
813 * Adapted from [vscode-java](https://github.com/redhat-developer/vscode-java)
914 */
1015export class ClientErrorHandler implements ErrorHandler {
1116
1217 private restarts : number [ ] ;
1318 private name : string ;
19+ private context : ExtensionContext ;
20+ private heapDumpFolder : string ;
1421
15- constructor ( name : string ) {
22+ constructor ( name : string , context : ExtensionContext ) {
1623 this . name = name ;
1724 this . restarts = [ ] ;
25+ this . context = context ;
26+ this . heapDumpFolder = getHeapDumpFolderFromSettings ( ) || context . globalStorageUri . path ;
1827 }
1928
2029 error ( _error : Error , _message : Message , _count : number ) : ErrorAction {
@@ -23,6 +32,17 @@ export class ClientErrorHandler implements ErrorHandler {
2332
2433 closed ( ) : CloseAction {
2534 this . restarts . push ( Date . now ( ) ) ;
35+ const heapProfileGlob = new glob . GlobSync ( `${ this . heapDumpFolder } /java_*.hprof` ) ;
36+ if ( heapProfileGlob . found . length ) {
37+ // Only clean heap dumps that are generated in the default location.
38+ // The default location is the extension global storage
39+ // This means that if users change the folder where the heap dumps are placed,
40+ // then they will be able to read the heap dumps,
41+ // since they aren't immediately deleted.
42+ cleanUpHeapDumps ( this . context ) ;
43+ showOOMMessage ( ) ;
44+ return CloseAction . DoNotRestart ;
45+ }
2646 if ( this . restarts . length < 5 ) {
2747 return CloseAction . Restart ;
2848 } else {
@@ -37,3 +57,48 @@ export class ClientErrorHandler implements ErrorHandler {
3757 }
3858
3959}
60+
61+ /**
62+ * Deletes all the heap dumps generated by Out Of Memory errors
63+ *
64+ * @returns when the heap dumps have been deleted
65+ */
66+ export async function cleanUpHeapDumps ( context : ExtensionContext ) : Promise < void > {
67+ const heapProfileGlob = new glob . GlobSync ( `${ context . globalStorageUri . path } /java_*.hprof` ) ;
68+ for ( let heapProfile of heapProfileGlob . found ) {
69+ await fs . remove ( heapProfile ) ;
70+ }
71+ }
72+
73+ /**
74+ * Shows a message about the server crashing due to an out of memory issue
75+ */
76+ async function showOOMMessage ( ) : Promise < void > {
77+ const DOCS = 'More info...' ;
78+ const result = await window . showErrorMessage ( 'The XML Language Server crashed due to an Out Of Memory Error, and will not be restarted. ' , //
79+ DOCS ) ;
80+ if ( result === DOCS ) {
81+ await commands . executeCommand ( ClientCommandConstants . OPEN_DOCS ,
82+ {
83+ page : 'Troubleshooting' ,
84+ section : 'the-language-server-crashes-due-to-an-out-of-memory-error'
85+ }
86+ ) ;
87+ }
88+ }
89+
90+ const HEAP_DUMP_FOLDER_EXTRACTOR = new RegExp ( `${ HEAP_DUMP_LOCATION } (?:'([^']+)'|"([^"]+)"|([^\\s]+))` ) ;
91+
92+ /**
93+ * Returns the heap dump folder defined in the user's preferences, or undefined if the user does not set the heap dump folder
94+ *
95+ * @returns the heap dump folder defined in the user's preferences, or undefined if the user does not set the heap dump folder
96+ */
97+ function getHeapDumpFolderFromSettings ( ) : string {
98+ const jvmArgs : string = workspace . getConfiguration ( 'xml.server' ) . get ( 'vmargs' ) ;
99+ const results = HEAP_DUMP_FOLDER_EXTRACTOR . exec ( jvmArgs ) ;
100+ if ( ! results || ! results [ 0 ] ) {
101+ return undefined ;
102+ }
103+ return results [ 1 ] || results [ 2 ] || results [ 3 ] ;
104+ }
0 commit comments