roadrunner22x
Grünschnabel
Hallo hier lieben,
meine Jar-Applikation ist an den Rand des Möglichen gestoßen. Auch mir blieb nix anderes mehr möglich als das Programm mit höheren "Java Heap Size"- Werten (kurz JHS) zu starten. Aber wie?
Mit diesem Beitrag möchte ich meinen Umsetzung vorstellen, um erstens eine mögliche Gedankenstütze zu geben und zweiten euch aufwendige Recherchezeit zu ersparen.
Das Programm wird später nicht von mir genutzt und dem User erklären, dass er ein Batch/Shell starten soll oder wo möglich noch eine Konsole öffnen muss und dort was rein hacken, geht mir persönlich zu weit und hat nix mit Usability zu tun.
Aus diesem Grund habe ich mir, danke dem Background-Wissen von "tutorials.de" und "google", eine kleine Klasse geschrieben, die durch den Aufruf
prüft, ob die aktuelle JHS der JVM größer gleich der gewünschten JHS ist. Sollte dies nicht so sein, wird ein Restart der eigenen Applikation, mit den neuen JHS-Werten, erzwungen.
Aber da kommen wir schon zur eigentlichen Problematik. In Java ist es momentan(vielleicht später mal) nicht möglich, einem laufenden Programm zusagen "schließe dich und starte neu". Damit meine ich nicht, gaphisch was neu zeichen oder so, sondern einen sauberen Neustart, wo möglich mit neuen Parametern für das Programm oder für die JVM.
Durch einen Workaround über eine Skript-Datei kann dies aber erwirkt werden. Dazu wird eine temporäre Skript-Datei geschrieben, welche den Befehl zum Start der Applikation beinhaltet. Danach wird diese in einem separaten Prozess aufgerufen und die alte Applikation beendet. Mit dem Start des neuen Programm, wird das temporäre Skript wieder gelöscht.
Jetzt werden einige sagen: "Java ist/soll plattformunabhängig sein!". Nun ja, aber irgendwann kommt man bei großen Projekten an den Punkt, wo es einfach nicht mehr geht und für jedes Betriebssystem spezifische Module entwickelt werden müssen. Das gleiche wurde auch hier umgesetzt bzw. muss noch umgesetzt werden. Jedes OS hat seine eigene Skriptsprache. Sei es durch eine Batch (Win), Shell (Linux) etc.
Die hier beschriebene Klasse wurde erst mal nur für Windows implementiert. Allerdings kann sie an den kommentierten Stellen entsprechende erweitert werden.
Durch die Modifizierung dieser JHS-Werte kann diese Prüfung entsprechend geändert werden.
Wie bereits erwähnt, ist die hier vorgestellte Klasse vorrangig für Windows ausgelegt. Kann aber beliebig erweitert werden. Wer Verbesserungsvorschläge hat, kann gerne seine Meinung hierzu schreiben.
Ich hoffe ich konnte dem einen oder anderen weiter helfen.
Liebe Grüße
de roadrunner ;-)
meine Jar-Applikation ist an den Rand des Möglichen gestoßen. Auch mir blieb nix anderes mehr möglich als das Programm mit höheren "Java Heap Size"- Werten (kurz JHS) zu starten. Aber wie?
Mit diesem Beitrag möchte ich meinen Umsetzung vorstellen, um erstens eine mögliche Gedankenstütze zu geben und zweiten euch aufwendige Recherchezeit zu ersparen.
Das Programm wird später nicht von mir genutzt und dem User erklären, dass er ein Batch/Shell starten soll oder wo möglich noch eine Konsole öffnen muss und dort was rein hacken, geht mir persönlich zu weit und hat nix mit Usability zu tun.
Aus diesem Grund habe ich mir, danke dem Background-Wissen von "tutorials.de" und "google", eine kleine Klasse geschrieben, die durch den Aufruf
Code:
public static void main(String[] args)
{
SystemHeapSpace.checkNeedToRestart(args);
...
}
Aber da kommen wir schon zur eigentlichen Problematik. In Java ist es momentan(vielleicht später mal) nicht möglich, einem laufenden Programm zusagen "schließe dich und starte neu". Damit meine ich nicht, gaphisch was neu zeichen oder so, sondern einen sauberen Neustart, wo möglich mit neuen Parametern für das Programm oder für die JVM.
Durch einen Workaround über eine Skript-Datei kann dies aber erwirkt werden. Dazu wird eine temporäre Skript-Datei geschrieben, welche den Befehl zum Start der Applikation beinhaltet. Danach wird diese in einem separaten Prozess aufgerufen und die alte Applikation beendet. Mit dem Start des neuen Programm, wird das temporäre Skript wieder gelöscht.
Jetzt werden einige sagen: "Java ist/soll plattformunabhängig sein!". Nun ja, aber irgendwann kommt man bei großen Projekten an den Punkt, wo es einfach nicht mehr geht und für jedes Betriebssystem spezifische Module entwickelt werden müssen. Das gleiche wurde auch hier umgesetzt bzw. muss noch umgesetzt werden. Jedes OS hat seine eigene Skriptsprache. Sei es durch eine Batch (Win), Shell (Linux) etc.
Die hier beschriebene Klasse wurde erst mal nur für Windows implementiert. Allerdings kann sie an den kommentierten Stellen entsprechende erweitert werden.
Code:
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author roadrunner22x
*
*/
public class SystemHeapSpace {
/**
* start java heap size
*/
private final static String initJavaSize = "128m";
/**
* Maximum java heap size
*/
private final static String maxiJavaSize = "512m";
/**
* Reference threshold at the desired maximum heap size
*/
private final static long referenceMaxJavaSize = 400000000;
/**
* This method examines the need for a restart. This is based on the size of the maximum java heap size of
* JVM and the desired maximum java heap size.
* @param parameters - arguments on startup
* @return
*/
public static boolean checkNeedToRestart(String [] parameters)
{
delTempBatchFile();
if (getMaxHeapSpace() < referenceMaxJavaSize)
{
try {
restart(parameters);
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
/**
* This method returns the maximum Java Heap Space size.
* @return maximum Java Heap Space as long
*/
public static long getMaxHeapSpace(){
return Runtime.getRuntime().maxMemory();
}
/**
* This method starts the newly downloaded java file and terminate the current program.
* @throws IOException
*/
private static void restart(String [] parameters) throws IOException
{
String command = filterOnOSSystem(parameters, System.getProperty("java.class.path"));
Runtime.getRuntime().exec(command);
System.exit(0);
}
/**
* This method filters the current operting sytem and calls the corresponding sub-function.
* @param parameters - arguments on startup
* @param jarFile - jar file path/ jar file name
* @return start instructions for your operating system
* @throws IOException
*/
private static String filterOnOSSystem(String [] parameters, String jarFile) throws IOException
{
if (System.getProperty("os.name").toLowerCase().startsWith(new String("windows")))
return winScriptFile(parameters, jarFile);
else if (System.getProperty("os.name").toLowerCase().startsWith(new String("linux")))
return linuxScriptFile(parameters, jarFile);
/*
* diese "wenn, dann, sonst" Methode kann durch weiter Abfrage andere Betriebsysteme prüfen,
*/
else
return null;
}
/**
* This method write a temporay batch file for restart the application in a microsoft windows system.
* @param parameters - arguments on startup
* @param jarFile - jar file path/ jar file name
* @return a microsoft windows start instructions
* @throws IOException
*/
private static String winScriptFile (String [] parameters, String jarFile) throws IOException
{
/*
* Inhalt der Batch-Datei erzeugen
* Dabei ist darauf zu achten, das bei einer Parameter-Mitgabe ein extra Fenster
* angezeigt werden muss. Dies wird durch den Unterschied mit "java" und javaw"
* erzeugt.
*/
StringBuilder param = new StringBuilder();
for (String para: parameters){
param.append(" "+para);
}
StringBuilder command = null;
if (parameters.length > 0)
command = new StringBuilder( "start java " +
"-Xms"+initJavaSize+" " +
"-Xmx"+maxiJavaSize+" " +
"-jar " +
jarFile + param + "\r\n" +
"exit");
else
command = new StringBuilder( "start javaw " +
"-Xms"+initJavaSize+" " +
"-Xmx"+maxiJavaSize+" " +
"-jar " +
filterJarFileName(jarFile) + "\r\n" +
"exit");
/*
* Datei anlegen und beschreiben
*/
File fWin = new File("tempBatch.bat");
FileWriter fwWin = new FileWriter(fWin);
fwWin.write(command.toString());
fwWin.flush();
fwWin.close();
return "cmd /C start /MIN " + fWin.getName() + " exit";
}
/**
* This method write a temporay batch file for restart the application in a linux system.
* @param parameters - arguments on startup
* @param jarFile - jar file path/ jar file name
* @return a linux start instructions
* @throws IOException
*/
private static String linuxScriptFile (String [] parameters, String jarFile) throws IOException
{
StringBuilder command = new StringBuilder();
/*
* Hier müssen jetzt die Befahle für linux hin
*/
File fLinux = new File("tempBatch.sh");
FileWriter fwLinux = new FileWriter(fLinux);
fwLinux.write(command.toString());
fwLinux.flush();
fwLinux.close();
return null;
}
/**
* This method filters out from the given jar file path to the file name.
* @param jarFileName - jar file path
* @return jar file name
*/
private static String filterJarFileName(String jarFileName)
{
int lastPathFind = 0;
/*
* bei Doppelklick auf ein Jar-File gibt "System.getProperty(java.class.path)"
* den gesamten Dateipfad aus. Dieser muss erst weg rationalisiert werden.
*/
if (-1 == (lastPathFind = jarFileName.lastIndexOf(System.getProperty("file.separator"))))
lastPathFind = 0;
else
lastPathFind++;
return jarFileName.substring(lastPathFind, jarFileName.length());
}
/**
* This method delet all temporary files.
*/
private static void delTempBatchFile() {
File f = new File("./");
File [] fList = f.listFiles();
for (File tempF : fList){
if (tempF.getName().equals("tempBatch.bat"))
tempF.delete();
if (tempF.getName().equals("tempBatch.sh"))
tempF.delete();
/*
* Hier kann noch erweitert werden, durch weitere Skript-Files
* anderer Betriebsysteme.
*/
}
}
}
Durch die Modifizierung dieser JHS-Werte kann diese Prüfung entsprechend geändert werden.
Code:
/**
* start java heap size
*/
private final static String initJavaSize = "128m";
/**
* Maximum java heap size
*/
private final static String maxiJavaSize = "512m";
/**
* Reference threshold at the desired maximum heap size
*/
private final static long referenceMaxJavaSize = 400000000;
Wie bereits erwähnt, ist die hier vorgestellte Klasse vorrangig für Windows ausgelegt. Kann aber beliebig erweitert werden. Wer Verbesserungsvorschläge hat, kann gerne seine Meinung hierzu schreiben.
Ich hoffe ich konnte dem einen oder anderen weiter helfen.
Liebe Grüße
de roadrunner ;-)
