[Java] Riesiges String-Array?

MCStreetguy

Stammuser
Hallo liebe Community :)

Ich arbeite grade als schulisches Projekt an einem Programm das auf Basis des Brute-Force-Prinzips eine Passwortliste mit angegebenen Zeichensatz und angegebener maximaler Passwortlänge.
Mein Algorithmus ist komplett fertig und funktioniert theoretisch auch aber ich stoße auf ein großes Problem :/
Ich speichere die generierten Passwörter in einem String-Array, welches ab einer Länge von 5 oder mehr leider nicht mehr ordnungsgemäß funktioniert :/
Ab da bekomme ich von Eclipse beim Kompilieren die Fehlermeldung
Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
angezeigt :/

Könnt ihr mir eventuell verraten wie ich entweder die Begrenzungen der VM erweitern kann oder ein geeigneteres Verfahren um die Passwörter temporär zu speichern? :)

Danke im Vorraus, MCStreetguy :)
 

CDW

Moderator
Mitarbeiter
wie ich entweder die Begrenzungen der VM erweitern kann
z.B die VM so starten:
Code:
java -Xmx1024m app
(hebt das Maximum auf 1024 MB, man kann auch größere Werte angeben ;))
siehe: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html#BABHDABI part mit "-Xmxsize".

Allerdings gibt es da ein kleines Problem mit der Anzahl der möglichen Kombinationen ;) (diese kann man berechnen, in dem man "Anzahl der Möglichkeiten pro Stelle/Zeichen" hoch (https://de.wikipedia.org/wiki/Potenz_(Mathematik)) Anzahl der Stellen nimmt.
d.h z.B Anzahl der möglichen Passwörter mit Groß/Kleinbuchstaben der Länge 5 und 6:
Code:
>>> 52 ** 5
380204032
>>> 52 ** 6
19770609664
Und das sind "mal eben": Anzahl der Kombination * (Wortlänge + Zeilenumbruch) Bytes:
Code:
>>> 52**6 * (6+1)
138394267648
>>> 52**5 * (5+1)
2281224192
>>> # oder in GB
>>> 52**5 * (6+1) / 1024 / 1024 / 1024
2 #GB
>>> 52**6 * (6+1) / 1024 / 1024 / 1024
128 #GB
Der Speicher kann also schon bei "läppischen" fünfstelligen Passwörtern recht knapp werden ;)

oder ein geeigneteres Verfahren um die Passwörter temporär zu speichern?
Eine Datei ist fein.
Dazu braucht man eigentich nichts weiter, als die Passwörter auszugeben (Konsole) und die Ausgabe in eine Datei umleiten (die man auch noch bei Bedarf komprimieren kann):
Code:
CDW@highlander-jr:/tmp % wordlist "abcdefghijklmnopqrst" -M 5 > pass 
CDW@highlander-jr:/tmp % wordlist "abcdefghijklmnopqrst" -M 5 | xz > pass.xz       
CDW@highlander-jr:/tmp % ls -l pass*   
CDW@highlander-jr:/tmp % ls -lh pass*
-rw-r-----  1 CDW  wheel    19M 21 Sep 22:55 pass
-rw-r-----  1 CDW  wheel   490K 21 Sep 22:55 pass.xz
 

Tsjuder

Stammuser
Mit Quellcode wäre es einfacher.

Was versuchst du denn jetzt genau? Das hört sich für mich erst mal leicht widersprüchlich an: Generierst du jetzt Passwörter oder nutzt du eine Passwortliste?

Folgendes könnte helfen:
1. Zeig mal den Code wie du das Array generierst. Ein Array der Größe 5 sollte locker klappen es sei denn deine Strings reservieren unfassbar viel Speicherplatz.
2. Wenn du eine Passwortliste nutzt: Lies immer nur eine handvoll Strings ein und probiere diese aus. Z.B. eine Text Datei mit 500 Millionen Passwörter. Dabei würde es wohl reichen einfach immer nur maximal 500 000 Passwörter einzulesen, auszuprobieren und anschließend die nächsten 500 000 einzulesen.
3. Wenn du die Passwörter generierst: Warum überhaupt speichern? Es reicht doch nur das aktuelle zu kennen, solange du irgendein Algorithmus hast, der tatsächlich nach Beendigung alle Passwörter ausprobiert hat.


EDIT:
z.B die VM so starten:
Code:
java -Xmx1024m app
(hebt das Maximum auf 1024 MB)
siehe: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html#BABHDABI part mit "-Xmxsize".

Das sollte aber IMO auch nix bringen. Der Fehler sagt aus, dass das Array so groß nicht sein darf. Wenn tatsächlich zu wenig Speicher vorhanden ist zum allozieren, würde erst später ein entsprechender Heap Space Fehler geworfen werden.
 
Zuletzt bearbeitet:

CDW

Moderator
Mitarbeiter
Das sollte aber IMO auch nix bringen. Der Fehler sagt aus, dass das Array so groß nicht sein darf. Wenn tatsächlich zu wenig Speicher vorhanden ist zum allozieren, würde erst später ein entsprechender Heap Space Fehler geworfen werden.
Hm, so wie ich die Beschreibung verstanden habe, wird die Meldung dann herausgehauen, wenn der Heap für das Array zu klein ist :confused:
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks002.html
Exception in thread thread_name: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
Cause: The detail message "Requested array size exceeds VM limit" indicates that the application (or APIs used by that application) attempted to allocate an array that is larger than the heap size. For example, if an application attempts to allocate an array of 512 MB but the maximum heap size is 256 MB then OutOfMemoryError will be thrown with the reason Requested array size exceeds VM limit.
Action: Usually the problem is either a configuration issue (heap size too small), or a bug that results in an application attempting to create a huge array (for example, when the number of elements in the array is computed using an algorithm that computes an incorrect size).
 

Tsjuder

Stammuser
Hi CDW,
interessant...ich kenne die Fehlermeldung nur, wenn man versucht zu viele Elemente für ein Array erzeugen.

Ich habe mal folgende Testcode mit 4 GB Heap Space gestartet:
Code:
public class ArrayTest {

	public static void main(String[] args) {
		System.out.println("Integer.MAX_VALUE: " + Integer.MAX_VALUE);
		
		System.out.println("Test 1: Zu viele Indizes");
		try {
			byte[] arr = new byte[Integer.MAX_VALUE - 1];
			System.out.println("Alles OK");
		} catch (Throwable t) {
			System.out.println(t.toString());
		}
		System.out.println("Test 1: Beendet");
		
		System.out.println("Test 2: Weniger Indizes, genug Speicher");
		try {
			byte[] arr = new byte[Integer.MAX_VALUE - 2];
			System.out.println("Alles OK");
		} catch (Throwable t) {
			System.out.println(t.toString());
		}
		System.out.println("Test 2: Beendet");
		
		System.out.println("Test 3: Weniger Indizes, nicht genug Speicher");
		try {
			long[] arr = new long[Integer.MAX_VALUE - 2];
			System.out.println("Alles OK");
		} catch (Throwable t) {
			System.out.println(t.toString());
		}
		System.out.println("Test 3: Beendet");
	}

}

Ausgabe:
Code:
Integer.MAX_VALUE: 2147483647
Test 1: Zu viele Indizes
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
Test 1: Beendet
Test 2: Weniger Indizes, genug Speicher
Alles OK
Test 2: Beendet
Test 3: Weniger Indizes, nicht genug Speicher
java.lang.OutOfMemoryError: Java heap space
Test 3: Beendet

Wie du siehst erhalte ich die "Requested array size exceeds VM limit" Fehlermeldung, wenn die Elementanzahl fast dem Integer.MAX_VALUE entspricht. Wenn die Elemente tatsächlich nicht alloziert werden können, die Heap Space Fehlermeldung.
 

CDW

Moderator
Mitarbeiter
Halb-OT:
Hi CDW,
interessant...ich kenne die Fehlermeldung nur, wenn man versucht zu viele Elemente für ein Array erzeugen.
Das habe ich auch nicht anzweifeln wollen ;). Unter OpenJDK8 ist das Verhalten, wie von Dir beschrieben. Oracles JDK/JRE habe ich nicht zur Hand.

Ich muss gestehen, in den letzen 5 Jahren auch nichts mehr "Ernsthaftes" mit JVMs & Co gemacht zu haben - dass aber die offizielle Dokumentation, sowohl für 6,7 wie auch 8
Troubleshooting Memory Leaks - Troubleshooting Guide for Java SE 6 with HotSpot VM
https://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/memleaks.html#gbyvi
"munter" die eben die oben zitierte "Ursache/Lösung" liefert, ist schon ziemlich "oraclig" :rolleyes:
 
Oben