# Jar-Neustart mit geänderten Java Heap Size



## roadrunner22x (7. März 2011)

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 

```
public static void main(String[] args)
{	
	SystemHeapSpace.checkNeedToRestart(args);
	...
}
```
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._


```
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. 

```
/**
 * 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 ;-)


----------



## wakoz (8. März 2011)

Dazu hätte ich eine Frage 

Es gibt Zahlreiche Projekte die sich mit dem Starten von Java Anwendungen beschäftigen, hast du dich mit denen beschäftigt?

In genau diesen kann man zum Beispiel Windows typischer eine EXE generieren welche mit definierten Heap Size Startet.
Wobei dein weg eleganter ist 

Oder zum Beispiel die Anwendung mit Scripten auszugeben welche ebenso die Anwendung starten.
Die Scripte die man Im Vorfeld schreiben kann, welche der User einfach nur starten muss um die Java Anwendung zu Starten. Und die Scripte von dem Programm aus zu modifizieren ist auch möglich. Wobei dieses deiner Lösung ja gleich kommt.

Um die Unabhängigkeit zu gewährleisten könnte man aus der Anwendung heraus das OS ermitteln und die nötigen Scripte zu manipulieren.


----------



## roadrunner22x (10. März 2011)

Hallo,

@wakoz:


> Es gibt Zahlreiche Projekte die sich mit dem Starten von Java Anwendungen beschäftigen, hast du dich mit denen beschäftigt?


Dazu muss ich dir sagen, dass mir bei der Recherche, kein Projekt aufgefallen ist, dass entsprechend meiner Vorstellungen die Problematik umgesetzt hat.



> ...die Anwendung mit Scripten auszugeben welche ebenso die Anwendung starten. ...


Die Prämisse liegt darauf, dass dem User nur eine Datei zugesendet wird. Dies hatte ich versucht zu sagen durch die Worte:


> ...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.


Des Weiteren muss ich dich mal fragen, ob du überhaupt eine Zeile meines Beitrages gelesen hast. Dabei wäre dir aufgefallen, das die Klasse bereits temporäre Skript zum Programmneustart nutzt.



> Um die Unabhängigkeit zu gewährleisten könnte man aus der Anwendung heraus das OS ermitteln und die nötigen Scripte zu manipulieren.



Wenn du meinen Beitrag richtig gelesen hättest, dann wäre dir aufgefallen, dass ich an mehreren Stellen erwähnt habe, dass die Klasse nicht nur ausschließlich für Windows-System konzipiert ist. Du solltest dir mal die Methode _*filterOnOSSystem(String [] parameters, String jarFile)*_ anschauen. Dort wird das OS ausgelesen und entsprechend weiter verfahren.

Ich danke dir für deinen Beitrag, dennoch bitte ich dich, dass nächste Mal genauer zu lesen, bevor du meinst etwas schreiben zu müssen.

@all:
Die Klasse funktioniert ausschließlich mit JARs. Während der Entwicklung habe ich "eclipse" genommen. Bei dieser IDE, kann man in den Properties den HeapSize einstellen

Gruß
de roadrunner ;-)


----------



## benhaze (10. März 2011)

Was spricht denn dagegen den HeapSpace (-xmx) direkt höher anzusetzen?
Wenn die Anwendung doch sowieso mit höheren HeapSpace (neu-)gestartet wird.

Außerdem:
In der netbeans.conf steht folgendes:


> # Note that a default -Xmx is selected for you automatically.



Möglicherweise hilt dir da der Code von NetBeans weiter...


----------



## roadrunner22x (11. März 2011)

benhaze hat gesagt.:


> Was spricht denn dagegen den HeapSpace (-xmx) direkt höher anzusetzen?


 
Dann musst du mir mal bitte erklären, wenn man nur eine Jar-File vorliegen hat, wie man standardmäßig einen höheren JavaHeapSize angeben kann. Na da bin ich mal auf deine Antwort gespannt.

Es ist mir schon bekannt, dass man wärend der Programmierung mit "Eclipse" oder "Netbeans" einen höheren HeapSize in den Parametern angeben kann. Nun hilft das aber nix, wenn das Projekt fertig ist und man nur noch mit der ausführbaren Datei rum rennt.

Lieben Gruß
de roadrunner ;-)


----------



## benhaze (11. März 2011)

Du wirst nicht um ein Script oder ApplStarter herumkommen.
Erstell ein zweites JAR, welches das Erste mit den gewünschten Parametern startet.
Das ApplStartet-Jar und dein echtes JAR könntest du auch in ein JAR packen!
Somit hast du nur ein JAR (inkl. ApplStarterClass).


----------



## hansmueller (14. März 2011)

Hallo roadrunner22x,

ich finde deine Lösung super. 
Noch besser finde ich, daß du sie anderen zur Verfügung stellst.
Und laß die Trolle, die deinen Beitrag nicht mal richtig gelesen haben, einfach links liegen.
Was die da von sich geben ist einfach nur peinlich.

MfG
hansmueller


----------



## wakoz (14. März 2011)

@roadrunner

danke für den Tipp, aber du weißt anscheinend gar nicht was du geschrieben hast

Im ersten Beitrag schreibst du 



> Wie bereits erwähnt, ist die hier vorgestellte Klasse vorrangig für Windows ausgelegt. ....


jetzt soll es auf einmal Plattform unabhängig sein?

Des weiteren habe ich auf deine Methode ein Script zu manipulieren Bezug genommen, nur finde ich es umständlich das Programm einmal zu starten  um es dann Neuzustarten nur damit der heapsize stimmt. Man könnte auch anstelle einer Tempfile eine normale Datei beim ersten Start erzeugen lassen und dies als INI immer wieder verwenden ohne bei jedem Programmstart zweimal zu starten. Dazu kommt das was benhaze geschrieben hat.

Zip archive kann jeder entpacken und es wäre im ersten Moment immer noch eine Datei.
es gibt zahlreiche Installer die alle datein entpacken, also eine Setup Datei zusenden.
Alternativen brauchen wir nicht ansprechen, denn diese machen alles Plattform abhängig.


Und nur weil du nicht verstehst was ich sagen will, heißt es nicht das ich deinen Beitrag nicht versehe 


die Möglichkeit die Heapsize im "Laufenden" System zu manipulieren finde ich klasse, nicht zuletzt weil man nicht immer die Heapsize vorher kennen kann. Ich denke da an Apache POI.
Aber dein Weg ist umständlich und die Verbesserungs Ideen von uns musst du nicht kaputt schreiben.


----------



## benhaze (15. März 2011)

@HansMueller


hansmueller hat gesagt.:


> Und laß die Trolle, die deinen Beitrag nicht mal richtig gelesen haben, einfach links liegen.
> Was die da von sich geben ist einfach nur peinlich.
> 
> MfG
> hansmueller


 
Da fühle ich mich direkt angesprochen.
Nur verstehe ich nicht wieso *Troll* und *peinlich*?
Ist das hier wirklich dein einziger Beitrag zu diesem Thema?
*Dein Beitrag ist einfach nur wertlos!*
_Sei doch wenigstens so nett und gib uns einen weniger *peinlichen* Tipp._

@roadrunner22x
Erstell doch einfach eine zweite Klasse (auch mit Main-Methode), die dein JAR mit den Parametern startest, die du brauchst.

anders ausgedrückt:



> java -jar deineApp.jar


macht folgendes:


> java -cp %DEIN_CP% -Xmx 500m -dein.classpath.zur.echten.anwendung.ClassMitMainMethode



Damit hast du nur eine JAR-Datei, allerdings mit 2 Main-Methoden.
MainMethode1 erstellt einen neuen Java-Prozess mit MainMethode2.
MainMethode1 ist in der JAR-Manifest deklariert.

Den Code zum Starten hast du ja schon.

Wenn dein JAR eh nur unter Windows Verwendung findet, kannst du auch LAUNCH4J benutzen.


----------



## hansmueller (15. März 2011)

benhaze hat gesagt.:
			
		

> Sei doch wenigstens so nett und gib uns einen weniger *peinlichen* Tipp.


Ok... dann werde ich mal was versuchen, aber bitte nicht zu viel erwarten.

Ich würde ProcessBuilder.start() statt Runtime.getRuntime().exec() verwenden. Habe mal irgendwo gelesen, daß ProcessBuilder neuer und besser sein soll.

Auch würde ich nicht extra ein Script auf die Platte schreiben und dieses dann ausführen.
Ich würde alle Komandos der Reihe nach in den ProcessBuilder stopfen. Das klappt ganz gut. Habe mir mal auf diese Art ein (Java-)Programm geschrieben, daß meine java-Dateien kompiliert, in eine Jar packt und diese Jar anschließend signiert. (Natürlich war für jeden dieser Schritte ein eigener ProcessBuilder notwendig.)

Eine ganz andere Möglichkeit wäre evtl. WebStart. Da kann man gleich für den Programmstart diverse Parameter festschreiben (über die JNLP-Datei). 
Kommt halt darauf an, wie man das Programm vertreiben will.

@benhaze: Eine Jar mit 2 Main-Methoden, eine zum Programmstarten und eine für das eigentliche Hauptprogramm - auch eine Möglichkeit. Kann man da aber auch noch eine Möglichkeit einbauen, falls der Anwender bereits so schlau war, von sich aus die JHS zu erhöhen? (Die meisten Anwender sind DAUs, aber eben nicht alle.) Da finde ich den Lösungsansatz von roadrunner22x etwas eleganter, da alles in ein einziges Programm gepackt ist.

MfG
hansmueller


----------



## benhaze (15. März 2011)

> Kann man da aber auch noch eine Möglichkeit einbauen, falls der Anwender bereits so schlau war, von sich aus die JHS zu erhöhen?


Ja, könnte man auch.
In MainMethode1 prüfen wieviel Xmx zur Verfügung steht.
Wenn zu wenig, MainMethode2 (via ProcessBuilder) mit mehr HS starten.
_(Beide Klassen (mit Main1 und Main2) sind in der gleichen JAR-Datei.)_

Via WebStart gehts auch.
Dann braucht man aber auch min 2 Dateien (Jar + JNLP)
Dann kann man auch nen Skript dabei tun.

*Grundsätzlich sehe ich jetzt aber nicht so das große Problem oder Umstand die JAR über ein Skript zu starten.*
_Wie bereits erwähnt: Launch4J ist auch eine Möglichkeit._


----------



## roadrunner22x (16. März 2011)

benhaze hat gesagt.:


> _Wie bereits erwähnt: Launch4J ist auch eine Möglichkeit._


Dieses Tool kannte ich nicht und ist mir bei der Recherche nicht auffällig geworden. Aber beim überfliegen dieser Anwendung (http://launch4j.sourceforge.net/) ist mir aufgefallen, dass es ausschließlich für Windows konzipiert ist. Aber für den einen oder anderen sehr interessant.



benhaze hat gesagt.:


> *Grundsätzlich sehe ich jetzt aber nicht so das große Problem oder Umstand die JAR über ein Skript zu starten.*


Ich sehe da grundsätzlich auch kein Problem darin. Aber zwei Tatsachen würde ich gerne anführen:
1.)


			
				hansmueller hat gesagt.:
			
		

> ...(Die meisten Anwender sind DAUs, aber eben nicht alle.)...


2.)
Das Grundkonzept hinter ganzen Geschichte besteht auf "einer einzigen" ausführbaren Datei. Dabei möchte ich nochmal auf meinen ersten Beitrag zu diesem Thema verweisen:


			
				roadrunner22x  hat gesagt.:
			
		

> 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.


Das mit dem WebStarter hatte ich mir auch überlegt. Und das scheint auch eine sehr praktische Lösung zu sein, aber es wurde schon auf die 2 Dateien-Umsetzung hingewiesen. Was dem Grundkonzept widerspricht. Siehe den Vorraussetzungen innerhalb diesem Beitrages, etwas weiter unten.

Die Möglichkeit mit den zwei Jars in einem packen, hatte ich auch schon in anderen Foren gelesen. Dabei sind mir außer  "Pack einfach zwei Jars in einem, oder benutze zwei Main-Methoden (Punkt)", keine konkreten Lösungsansätze aufgefallen. Was hilft mir ein theoretischer Ansatz. Aus diesem Grund wählte ich den wohl etwas einfacheren Weg.



			
				hansmueller  hat gesagt.:
			
		

> Ich würde ProcessBuilder.start() statt Runtime.getRuntime().exec() verwenden. Habe mal irgendwo gelesen, daß ProcessBuilder neuer und besser sein soll.


Kannst du das noch etwas genauer erklären? Bzw. hast du einen Link für diese Aussage? Vielleicht kann man das ja wirklich verwenden.



			
				hansmueller  hat gesagt.:
			
		

> ... alle Komandos der Reihe nach in den ProcessBuilder ...


Dies hatte ich auch schon versucht, ohne Erfolg. Wenn der Java Heap Size geändert werden soll,  muss dieser mit dem Aufruf des Programms übergeben werden, das setzt aber einen separaten Prozess voraus. Aber du kannst mir gerne einen Implementierungsvorschlag unterbreiten.



			
				hansmueller  hat gesagt.:
			
		

> Kann man da aber auch noch eine Möglichkeit einbauen, falls der Anwender bereits so schlau war, von sich aus die JHS zu erhöhen?


Diese Prüfung übernimmt diese bereits "von Anfang an implementierte" Methode:

```
/**
     * 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;
    }
```



			
				wakoz  hat gesagt.:
			
		

> Aber dein Weg ist umständlich und die Verbesserungs Ideen von uns musst du nicht kaputt schreiben.


Ich muss hier keinen „kaputt schreiben“. Ich verweise nur auf meinen ersten Beitrag zu diesem Thema hin. Dieser erklärt ausführlich meine Umsetzung und den Background. Und wenn man diesen nicht richtig liest oder auch nicht richtig lesen will, kannst du oder wer auch immer seine Zeit auch sinnvoller nutzen, als hier etwas zuschreiben. Die meisten deiner Nachfragen oder so genannten Verbesserungsvorschläge werden mit dem ersten Beitrag erfüllt. 
Beispiele, gefällig?:
1.)


			
				wakoz  hat gesagt.:
			
		

> ...aus der Anwendung heraus das OS ermitteln ...


siehe:

```
filterOnOSSystem(String [] parameters, String jarFile)
```
2.)


			
				wakoz  hat gesagt.:
			
		

> ...Oder zum Beispiel die Anwendung mit Scripten auszugeben ...


siehe:


			
				roadrunner22x  hat gesagt.:
			
		

> Die Prämisse liegt darauf, dass dem User nur eine Datei zugesendet wird. ...



3.)
wakoz und benhaze haben mir bis zum heutigem Tag noch nicht sagen können, wie man den Java Heap Size zur „Laufzeit“ erhöhen kann. Den eine konkrete Umsetzung liegt mir von euch nicht vor. Ich kann ja euch nochmal die Voraussetzungen geben, vielleicht hilft das euch weiter:
- Das eigentliche Programm ist eine Standalone-Version
- keine Möglichkeit für Internet
- nur eine Jar, keine extra Batch, Shell etc. („temporär“ ist dies aber erlaubt, muss aber für User nicht sichtbar sein)
- User soll ausschließlich per „Doppelklick“ auf die Jar das Programm starten, keine Konsole oder Batch, Shell etc.
- der User sollte an seiner JVM nichts an den Einstellungen ändern müssen ( siehe http://www.duckware.com/pmvr/howtoincreaseappletmemory.html), da dieser meistens nicht in der Lage dazu ist.
- zusammenfassend ist sagen, ich gehe davon aus, dass der User so "dumm wie ein Sack Reis" ist. Das ist jetzt nicht böse gemeint, soll aber meine Lage verdeutlichen
4.)


			
				wakoz  hat gesagt.:
			
		

> jetzt soll es auf einmal Plattform unabhängig sein?


siehe:


			
				roadrunner22x  hat gesagt.:
			
		

> Wie bereits erwähnt, ist die hier vorgestellte Klasse vorrangig für Windows ausgelegt. Kann aber beliebig erweitert werden.


Für mich sind momentan erst mal nur Windows-Systeme interessant. Zukünftig werden auch andere Systeme betrachtet. Die Funktion „linuxScriptFile (String [] parameters, String jarFile)“ sollte zeigen an welche Stelle man „ beliebig erweitert“ kann, um eine Plattformunabhängigkeit zu erzielen.

Verstehst du was ich damit sagen will?!
Hätte "von und zu Gutenberg" seiner Arbeit auch genau gelesen, hätte er jetzt auch nicht die Probleme.

So lange mir einer keine „konkreten“ alternativen Lösungsvorschläge (auf Quellcode-Ebene) für ein autarkes Programm (entsprechend den Voraussetzungen die ich oben genannt habe) unterbreiten kann, glaube ich, dass ich einen guten Lösungsansatz produziert habe. Und durch eure Aussagen werde ich in meiner Meinung bestättigt.

@wakoz und @benhaze:
Ihr könnt mir gerne alternative Quelltext-Passagen zuschicken bzw. hier schreiben. Vielleicht kann man ja einen gemeinsamen Nenner oder eine exemplarische Lösung für dieses Problem finden.

Lieben Gruß
de roadrunner ;-)


----------



## hansmueller (16. März 2011)

Hallo,



			
				roadrunner22x hat gesagt.:
			
		

> Kannst du das noch etwas genauer erklären? Bzw. hast du einen Link für diese Aussage? Vielleicht kann man das ja wirklich verwenden.


Ok, hab mal ein bißchen gegoogelt. Den ProcessBuilder gibt es erst seit Java 5 und soll die Sache mit der Runtime ersetzen. Das Teil bietet anscheinen mehr Möglichkeiten als die Runtime-Geschichte. Habe hier mal auf die Schnelle diesen Link gefunden: http://www.java-tips.org/java-se-tips/java.util/from-runtime.exec-to-processbuilder.html



			
				roadrunner22x hat gesagt.:
			
		

> Wenn der Java Heap Size geändert werden soll, muss dieser mit dem Aufruf des Programms übergeben werden, das setzt aber einen separaten Prozess voraus. Aber du kannst mir gerne einen Implementierungsvorschlag unterbreiten.


Der seperate Prozess sollte eigendlich gegeben sein. Dafür ist ja das Runtime bzw. ProzessBuilder da. Muß allerdings zugeben, daß ich noch nie versucht habe mit einen Javaprogramm ein anderes bzw. das gleiche Java-Programm mit veränderter JHS zu starten. 
Für einen kurzen Moment müßte man ein und dasselbe Programm 2 mal auf dem Desktop haben.

Ich habe hier mal einen kleinen Code-Schnipsel:

```
Progjarsigner = new File(VerzeichnisJDK.getPath() + "\\bin\\jarsigner.exe");//Ist das Programm jarsigner.exe, welches ausgeführt werden soll.
//DateiKeyStore ist ein File, daß die Schlüssel verwaltet bzw. lagert.
//ftpassword ist ein Textfeld, in dem das zu benutzende Passwort steht.
//tfalias ist ein Textfeld, in dem der Name bzw. das Alias des Schlüsselpaares steht.
//VerzeichnisZiel ist der Ordner in dem sich die Datei Programm.jar befindet. Diese soll signiert werden.

try
				{
					pb4 = new ProcessBuilder("cmd", "/C", Progjarsigner.getAbsoluteFile().toString(), "-keystore", DateiKeyStore.getAbsoluteFile().toString(), "-storepass", tfpasswort.getText(), VerzeichnisZiel.getAbsolutePath() + "\\Programm.jar", tfalias.getText());
					
					pc4 = pb4.start();
				
					pc4.waitFor();
					
					
					if(pc4.exitValue() == 0)
	    			{
						
	    				Weiter = true;	//Alles hat funktioniert
						
	       			}
	    			else
	    			{
	    				Weiter = false;
	    				Meldung = "Fehler beim Signieren ->ABBRUCH\n";
	    				
	    			}
							
					
				}
				catch(Exception ex)
				{
					ex.printStackTrace();
					Weiter = false;
					Meldung = "Fehler beim Signieren ->ABBRUCH\n";
				}
```

Das ganze führt den Befehl: "C\rogramme\Java\jdkxxx\bin\jarsigner.exe -keystore C\fad\zu\dem\Keystore -storepass MeinPasswort C\fad\zum\zu\signierenden\Programm.jar NamedesSchlüsselpaares" aus. Durch das "cmd" und "/C" wird es in der Konsole ausgeführt.
Eigendlich sollte der folgende Code daher auch funktionieren:

```
pb4 = new ProcessBuilder("cmd", "/C", C:\Pfad\zur\java.exe, "-Xms" + initJavaSize, "-Xmx" + maxiJavaSize, "-jar", C:\Pfad\zum\zu\startenden\Programm.jar)
```

Ich habe das Teil jetzt nicht getestet, ist jetzt nur mal so schnell dahingeschrieben. (Weiß jetzt nicht, ob es nach dem -Xms und den -Xmx ein Leerzeichen braucht und ob man besser java.exe oder javaw.exe nimmt.)
Hoffe es hilft dir evtl. weiter.

MfG
hansmueller


----------



## benhaze (16. März 2011)

Wie ich aus deinen Posts erkennen kann, fehlen dir wichtige Grundlagen-Informationen.

1.
Das dein JAR via Doppelklick gestartet wird, liegt nicht an Java!

2.
Den konkreten Lösungsansatz erkennst du nicht, da dir offensichtlich die Grundlagen nicht ausreichen bekannt sind.

- Was passiert bei einem Doppelklick auf einer JAR ganz genau?
- Wofür ist die Manifest-Datei im JAR?
- Wofür ist die Main-Methode?
- Wie startet man ein JAVA-Programm via Konsole?

Wenn du diese Fragen wirklich beantworten kannst, verstehe ich absolut nicht, wie du meinen Lösungsansatz nicht erkennen kannst******

Erkläre uns bitte auch, wo zur Hölle der Unterschied liegt, zwischen:

Doppelklick auf EXE
und
Doppelklick auf BAT/CMD/SH

*BEDENKE:*
Die meisten DAUs( ! ) haben die Dateinamen-Erweiterung (unter Windows) ausgeblendet!
Das ist die Windows Standard-Einstellung!
(KEIN *DAU *WIRD DIESE EINSTELLUNG JEMALS ÄNDERN!)
*Das bedeutet:* Der DAU kann gar nicht erkennen, ob es sich um eine EXE oder BAT handelt.
Wenn die BAT-Datei dann auch noch wie folgt (für DAUs) benannt wird:
BITTE_KLICKEN_SIE_DOPPELT_AUF_DIESE_DATEI.bat
sollte es auch keine Probleme geben.

Der User muss auch nix in die Konsole tippen, wenn du nen Skript benutzt.
(naja, zumindest nicht mehr als sonst (linux))

*zu Webstart:*
Es ist korrekt, das du dann min. 2 Dateien hast.
Der User allerdings, bekommt diese gar nicht zu sehen.
Hast du eine Idee, wie man *üblicherweise *Webstart-Anwengunden startet?

ProcessBuilder:


```
public int importCert(String pathToKeyStore, String alias, String certFile, String storepass, String keypass)throws Exception
    {
        String pathToJavaHome = System.getenv("JAVA_HOME");
        File javaHome = new File(pathToJavaHome + "/bin");
        
        List<String> cmds = new ArrayList<String>();
        
        cmds.add(javaHome + "/keytool");
        cmds.add("-import");
        cmds.add("-v");
        cmds.add("-alias");
        cmds.add(alias);
        cmds.add("-trustcacerts");
        cmds.add("-file");
        cmds.add(certFile);
        cmds.add("-keypass");
        cmds.add(keypass);
        cmds.add("-storepass");
        cmds.add(storepass);
        cmds.add("-keystore");
        cmds.add(pathToKeyStore);

        ProcessBuilder pb = new ProcessBuilder(cmds); 
        pb = pb.redirectErrorStream(true);
        Process proc = pb.start();
        
        String text = "";    // Lesepuffer
        BufferedReader in;
        PrintWriter out = new PrintWriter(System.out);
        
        // Eingabestream holen
        in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        while ((text = in.readLine()) != null) 
        {
            out.println(text); 
            out.flush();
        }
        return proc.exitValue();
        
    }
```

Diesen Code kannst du als Beispiel benutzen.
Statt dem "/keytool" nimmst du einfach "/java"
und dann eben deine Parameter.

Zuletzt frage ich mich wie deine DAUs mit PDF-Dateien klarkommen? (oder gar mit LINUX ******)
Das Adobe-Reader(9)-Verzeichnis ist über 200 MB groß und beinhaltet über 500! Dateien.

*(Das sage ich, weil du gesagt hast: )*


> meine Jar-Applikation ist an den Rand des Möglichen gestoßen.


Ist sie das wirklich?
Oder bist du an den Rand deiner Möglichkeiten gestoßen?

Ich versuche gerne zu Helfen, aber auch hier macht der Ton die Musik.
Ob deine Lösung tatsächlich die Beste ist, nur weil dir niemand Code für ein *autarkes* Programm gibt was all deinen Vorstellungen entspricht?


----------



## hansmueller (17. März 2011)

Hallo,



			
				benhaze hat gesagt.:
			
		

> Den konkreten Lösungsansatz erkennst du nicht,



Doch, hat er, aber deine Lösung entspricht nicht ganz seinen Anforderungen:


			
				roadrunner22x hat gesagt.:
			
		

> Ich kann ja euch nochmal die Voraussetzungen geben, vielleicht hilft das euch weiter:
> - Das eigentliche Programm ist eine Standalone-Version
> - keine Möglichkeit für Internet
> - nur eine Jar, keine extra Batch, Shell etc. („temporär“ ist dies aber erlaubt, muss aber für User nicht sichtbar sein)
> ...


Was hier noch fehlt ist die Plattformunabhängigkeit. Also nicht nur Windows.



			
				benhaze hat gesagt.:
			
		

> Oder bist du an den Rand deiner Möglichkeiten gestoßen?
> 
> Ich versuche gerne zu Helfen, aber auch hier macht der Ton die Musik.


Wenn ich mir deine Beiträge so durchlese, dann hast du allerdings auch ganz schön kräftig auf die falschen Tasten gehaut.



			
				benhaze hat gesagt.:
			
		

> Ob deine Lösung tatsächlich die Beste ist, nur weil dir niemand Code für ein *autarkes* Programm gibt was all deinen Vorstellungen entspricht?


Er hat SEINEN Code hier gepostet. Es ist eine Lösung die SEINEN Anforderungen entspricht. SEINE Lösung funktioniert. Er läßt UNS daran teilhaben. 
Das einzige was von dir rüberkommt ist (Ist jetzt rein meine persönliche Meinung): "Was soll den dieser Unfug." und "Das macht man ganz anderst."
Jedenfalls kommen deine Beiträge so rüber. (Ist jetzt wirklich nur meine persönliche Meinung.)

Ach ja, bzgl. WebStart, wenn keine Internetverbindung vorhanden ist, ist WebStart hierfür wirklich keine gute Lösung. Ist zwar auch möglich, aber nicht sehr konfortabel.

MfG
hansmueller


----------



## benhaze (17. März 2011)

ja, manchmal ärgere ich mich etwas schnell:

1. meine Jar-Applikation ist an den Rand des Möglichen gestoßen.
2. wenn mir niemand das Gegenteil beweist (mit vollst. Code!), habe ich die beste Lösung.
3. die sinnlose Diskussion über all die Nachteile eines Start-Skripts (JAR oder BAT, der DAU siehts doch eh nicht)



> aber deine Lösung entspricht nicht ganz seinen Anforderungen


Welche seiner Anforderungen kann man denn nicht mit meiner Lösung abdecken?
_Ich rede von der Lösung mit den 2 Main-Methoden in einem JAR._


----------



## roadrunner22x (17. März 2011)

@benhaze:

Sorry, aber ab sofort kann ich nur noch über dich lachen. Wer hat 


			
				benhaze hat gesagt.:
			
		

> 2. wenn mir niemand das Gegenteil beweist (mit vollst. Code!), habe ich die beste Lösung.


das behauptet? Ich habe nur angedeutet, dass ich 


			
				roadrunner22x hat gesagt.:
			
		

> ...einen guten Lösungsansatz produziert habe.


Hier spricht keiner davon, der Bester zu sein oder das Beste programmiert zu haben.
Und zweitens, ich habe niemals und werde es auch niemals von jemanden verlangen meine Problematiken 





			
				benhaze hat gesagt.:
			
		

> ...mit vollst. Code!...


 zu lösen. Nur besteht eine massiver Unterschied zwischen der Aussage "Da kann man zwei Mains verwenden" und kleinen Quelltext-Passagen oder UML-Veranschaulichungen.



			
				benhaze hat gesagt.:
			
		

> 3. die sinnlose Diskussion über all die Nachteile eines Start-Skripts (JAR oder BAT, der DAU siehts doch eh nicht)


Ich werde es jetzt zum vierten mal wiederholen, dass ich und der Auftragsgeber zum starten keine Batch/Shell etc. verwenden wollen. Wenn du mir sagen kannst wie man eine Batch/Shell und eine Jar in eins packen kann, können wir sofort diese Diskussion beenden.

_ Ich sage auch nicht, dass es Nachteile mit Start-Skripten gibt, nur sollen sie hier einfach keine Verwendung finden. EINE DATEI MEHR NICHT!!_

Einer meiner ersten Aussagen war:


			
				roadrunner22x hat gesagt.:
			
		

> _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._


Und jetzt wo wir beim Ton sind - Sarkasmus -> "Eh Alter es gäht und das auch jut."
Ich hatte nur vor meine Lösungsvariante der Gemeinde vorzustellen. Ich musste viel Zeit in Recherche über Java Heap Size, Runtime, Batch und Shell investieren und wollte nur eine mögliche Offerte geben.

Mit diesen Worten verabschiede ich mich aus diese Diskussionsrunde, die ja keine ist. Es wird mir eine Lehre sein, hier nochmal zu "erdreisten" einen Beitrag zu schreiben.

Lieben Gruß
de roadrunner ;-)

P.S.: Natürlich werde ich mir die Beiträge mit  den kleinen Code-Beispiele von hansmueller und benhaze gründlich anschauen. Vielleicht kann man dort etwas für das eigene Projekt wahrnehmen.


----------



## benhaze (17. März 2011)

> Sorry, aber ab sofort kann ich nur noch über dich lachen.


Ok, das höre ich zwar zum ersten Mal hier, aber es freut mich für dich.

Ich will deinen Ansatz auch gar nicht verändern.
Wenn es so OK für dich ist, dann ist doch alles in Ordnung.

Mein Ansatz mit der Main-Methode, welche einfach eine weitere Main-Methode im gleichen JAR startet (via ProcessBuilder)
ist evtl. zu komplex. (trotz meines Code-Beispiels mit dem ProcessBuilder, welches der größte Part ist)
(obwohl er eigentlich ziemlich trivial ist)

Deine Vorstellungskraft reicht hier scheinbar nicht aus, um meinen Ansatz zu verstehen.

Hättest du wirklick eine **konkrete** Frage zu meinem Ansatz, hätte ich dir evtl. helfen können.
Dir aber deine Arbeit erledigen, wollte ich allerdings nicht. (es sind evtl. max 40 Zeilen CODE!)
Da du offensichtlich dafür bezahlt wirst (und nicht ich...)

Die Idee mit den temporären Skripten und dem Neustart hört sich doch ganz gut an.
Bleib einfach dabei. Besser (oder einfacher, oder sauberer) wird es wohl nicht gehen.

Der Thread könnte eigentlich als erledigt gekennzeichnet werden.
(Ich will hier jetzt auch keine Endlosdiskussion daraus machen)


----------



## genodeftest (17. März 2011)

Leute, bitte nicht rumzicken, das ist ein Forum.


----------

