# -Xmx1024m in JAR einbinden



## heinz86 (21. Sep 2011)

Hallo,

ist es möglich den Parameter -Xmx1024m, welcher es ermöglicht das Programm mit 1024 MB Arbeitsspeicher auszuführen mit in ein JAR-File geben, so dass die Applikation immer soviel Speicher bekommt? Benötige dies leider wegen aufwendigen String-Operationen...

Danke.


----------



## nrg (21. Sep 2011)

könnte man wenn dann über die manifest.mf setzen aber das geht afaik nicht


----------



## r.w. (21. Sep 2011)

heinz86 hat gesagt.:


> Hallo,
> 
> ist es möglich den Parameter -Xmx1024m, welcher es ermöglicht das Programm mit 1024 MB Arbeitsspeicher auszuführen mit in ein JAR-File geben, so dass die Applikation immer soviel Speicher bekommt? Benötige dies leider wegen aufwendigen String-Operationen...
> 
> Danke.



1 Gigabyte, nur für String-Operationen? 
Respekt! ;-)


----------



## Tobse (21. Sep 2011)

Ich glaube nicht, dass das so klug ist. Wenn auf dem Arbeitsspeicher keine 1024MB mehr da sind, bekomt java sie auch nicht -> das Programm startet nicht. Aus der Jar heraus evlt. sogar ohne fehlermeldung.
Wenn du das aber weglässt, kann es passieren, dass das OS java (ohne, das java es merkt) den übrigen, noch benötigten platz, auf der Festplatte zuschreibt und das Programm läuft, wenn auch nicht ganz so schnell.


----------



## heinz86 (21. Sep 2011)

Schonmal vielen Dank für die zahlreichen Antworten.
Vielleicht gibt es ja auch eine andere Möglichkeit. Ich lade eine Textdatei von 100MB und speichere den Inhalt in einem String. Diesen verschlüssele ich dann mit verschiedenen Verfahren. Und wenn ich den Arbeitsspeicher nicht heraufsetze, klappt dies einfach nicht, denn das Einlesen bricht einfach mit einer IO.Exception ab, dass der Java heap nicht ausreicht... Daher sah ich nur die Möglichkeit den Arbeitsspeicher zu erhöhen...
Vielleicht gibt es ja aber auch noch eine andere Möglichkeit?


----------



## Runtime (21. Sep 2011)

1. Was machst du mit dem verschlüsselten String? Behältst du den im RAM oder schreibst du den sofort in eine Datei?
2. Wenn du den String in kleine Teile schneidest, ist das Gesamtergebnis dann anders?


----------



## Spacerat (21. Sep 2011)

Was für Operationen machst du denn da? Bist du Speicherpathologe? :lol: Könnt ja sagen, dass man mit 'nem DirectByteBuffer diese Menge Speicher alloziieren kann, selbst wenn der Heap in dieser Hinsicht begrenzt ist, die Strings dann auch dort rein bekommt und letztendlich auch dort seine String-OPs durchführen kann. Aber während man hier da und dort an seinen eigenen Operations-Methoden bastelt, gelangt man schnell zu Einsicht, dass es Klassen gibt, die dass schon können -> StringBuffer und StringBuilder. Darüber hinaus macht man sogar die Erfahrung, dass String-OPs gar nicht so Speicheraufwendig sein müssen, wie Anfangs gedacht.


----------



## heinz86 (21. Sep 2011)

Hallo,
ich brauche den verschlüsselten String eigentlich nicht. Denn ich möchte nur ermitteln, wie lange die Verschlüsselung an sich benötigt.
Vielleicht kann man daran noch was optimieren...


----------



## Spacerat (21. Sep 2011)

Du musst also eigentlich nur wissen, wie lang die Textdatei ist. Dazu kannst die Klasse "File" verwenden. Wie lange aber diverse Verschlüsselungen brauchen hängt nicht nur von der Art ab, sondern auch von der Rechenleistung. Der Inhalt des Klartextes ist bei vielen Verschlüsselungsarten (z.B. RSA) aber weniger von Bedeutung. Deswegen würde es in den meisten Fällen auch genügen, ein mit 0 gefülltes Bytearray oder besser oben genannten DirectByteBuffer mit der Dateilänge verschlüsseln zu lassen.


----------



## heinz86 (21. Sep 2011)

Hallo,

die Idee klingt sehr spannend. Habe jetzt einfach mal nach File geschaut und mir File.length() ausgegeben. Bei einer 100MB großen Datei habe ich nun den Wert 105941950 erhalten. Nun erstelle ich also ein DirectByteArray von der Größe und schreibe dort nur 0en rein und lasse dieses verschlüsseln?


----------



## Spacerat (21. Sep 2011)

Die Nullen brauchst da nicht mal mehr reinschreiben...
	
	
	
	





```
Buffer b = myBuffer;
b.position(b.capacity() - 1);
b.flip();
```
Aber Vorsicht: ein DirectBuffer kann Speicherleaks verursachen und hat auch kein Array-Puffer. Daraus folgt, dass du in den Verschlüsselungsroutinen nur mit dem Puffer arbeiten kannst.


----------



## TheRealSpikee (22. Sep 2011)

Frag : warum packst du dir 100MB in den RAM ?
Cipher hat eine Methode die sich update(byte[]) nennt. Jetzt liest du einfach wie gewohnt mit nem Buffer das File ein jagst es gleich durch update(byte[]).
Am Ende noch das doFinal(byte[]) und gut ist.


```
public static String hash(File input) throws Exception
{
	MessageDigest md=MessageDigest.getInstance("SHA-256");
	FileInputStream fis=new FileInputStream(input);
	int br=0;
	byte[] buf=new byte[1024];
	while((br=fis.read(buf))!=-1)
	{
		md.update(buf, 0, br);
	}
	fis.close();
	byte[] output=md.digest();
	return ToolKit.byteArrayToHexString(output);
}
```

Das ist jetzt zwar nur ein SHA-256 Hasher ... aber damit kann ich auch Gigabyteweise hashen ohne den RAM anzuheben ... einfach nur weil ich mit nem Buffer von 1kB arbeite *ja ich weis ... ist nicht grade performant da der Buffer sehr klein ist ... aber es funktioniert*.

Und das jetzt mit Cipher aufzubauen sieht ähnlich aus.

btw : in der Praxis wird auch nicht erst das File komplett in den RAM geladen nur um dann die Geschwindigkeit fürs crypten darüber zu erreichen. Mit geeigneter Buffer-Größe ist es sogar schneller dierekt von der Platte aus zu lesen.


----------



## Guybrush Threepwood (22. Sep 2011)

Um noch einmal auf Deine anfängliche Frage zurück zu kommen: Es geht, wenn Du einen Wrapper, .bat / .sh-Datei oder Webstart nimmst. Aus einer .jar-Datei (Manifest) geht es nicht.


----------



## truesoul (22. Sep 2011)

Das könntest du aber machen:


```
// Anhand wieviel Speicher zur Verfügung steht.
        String min = ...;
        String max = ...;

        String userdir = System.getProperty("user.dir");
        // Konsolenstring
        String cmd = "java -Xms"+min+"m -Xmx"+max+"m -jar \""+userdir+"\\deineJar.jar\"";

        try {
            // Konsolenaufruf mit Stringeingabe
            Runtime.getRuntime().exec(cmd);
        } catch (IOException e) {
           
        }

        // Hier musst du die aktuelle Anwendung beenden mit z.B  System.exit()
```
Dies machst du ganz am Anfang der Anwendung. 
Und anstatt String würde ich StringBuffer verwenden. Damit ist das laden von einer solch großen Datei erheblich schneller. 

Bzw würde ich den Vorschlag von oben bevorzugen, zwei Post über mir.

Mfg


----------



## Lumaraf (22. Sep 2011)

Schau dir mal Launch4J an da kann man die Speichergröße die die VM später benutzen soll drin festlegen.


----------



## heinz86 (22. Sep 2011)

TheRealSpikee hat gesagt.:


> Frag : warum packst du dir 100MB in den RAM ?
> Cipher hat eine Methode die sich update(byte[]) nennt. Jetzt liest du einfach wie gewohnt mit nem Buffer das File ein jagst es gleich durch update(byte[]).
> Am Ende noch das doFinal(byte[]) und gut ist.
> 
> ...



Hallo,

die Idee ist recht gut, aber irgendwie scheitere ich gerade noch ein wenig an der Umsetzung.
Ich habe das ganze jetzt für eine Verschlüsselung mit Blowfish, wie folgt aufgebaut:

```
public static void encryptBlowfish(File inputFile) throws Exception {
		// Schluesselgenerator für 'Blowfish' erstellen
		KeyGenerator keygenerator = KeyGenerator.getInstance("Blowfish");

		// Schluessel erzeugen
		SecretKey secretkey = keygenerator.generateKey();

		// Chiffre erstellen
		Cipher cipher = Cipher.getInstance("Blowfish");

		// Chiffre initialisieren
		cipher.init(Cipher.ENCRYPT_MODE, secretkey);

		FileInputStream fis = new FileInputStream(inputFile);
		
		// Text verschluesseln
		int br = 0;
		byte[] buf = new byte[1024];
		
		while ((br = fis.read(buf)) != -1) {
			cipher.update(buf, 0, br);
		}
		fis.close();
	}
```

Dies orientiert sich ja an deinem Beispiel, nur dass ich keinen String am Ende erzeugen, da ich dieses ja auch nicht benötige. Nur nun sagt er mir, dass er zum Verschlüsselung einer 100MB großen Datei genau 0 Sekunden benötigt. Dies kann meiner Meinung aber nicht so recht angehen... Da muss also irgendwo noch ein Fehler drin sein...


----------



## TheRealSpikee (23. Sep 2011)

Na gut ... abgesehen davon das am Ende noch ein doFinal() fehlt sieht das so schon mal garnicht so schlecht aus.

Jetzt wäre die Frage : WIE misst du die Zeit ? Und kommt die Ausgabe : 0 Sekunden wirklich sofort oder dauert es bis das passiert *was eigentlich der Fall sein sollte*.

Ohne den Code der Zeitmessung werden wir dir hier nicht helfen können.


----------

