AutoIt Array Speicherfresser?????

  • hi

    wollte zum testen für speichergeschwindigkeiten bei Objecten ein array erstellen.
    bekam aber den fehler "Error allocating memory." von AutoIt ?( . zuerst kp warum, dachte mir was da los ist bei so einem mini array
    Autoit aufgeblasen auf knappe 3gb speicher 8o .

    hier mein array

    [autoit]

    Local $array[100][100]
    For $r = 0 To UBound($array) -1
    For $c = 0 To UBound($array, 2) -1
    Local $FeldZumSpeichern
    For $z = 0 To 300
    $FeldZumSpeichern &= Chr(Random(32, 126, 1))
    Next
    $array[$r][$c] = $FeldZumSpeichern
    Next
    Next

    [/autoit]

    kam eh sofort drauf wo der fehler lag

    [autoit]

    Local $array[100][100]
    For $r = 0 To UBound($array) -1
    For $c = 0 To UBound($array, 2) -1
    Local $FeldZumSpeichern = ""
    For $z = 0 To 300
    $FeldZumSpeichern &= Chr(Random(32, 126, 1))
    Next
    $array[$r][$c] = $FeldZumSpeichern
    Next
    Next

    [/autoit]

    Kleiner fehler große wirkung ;)
    aber das dass so viel speicher braucht?
    bin mal gespannt ob das erste array bei euch funzt ^^

    mfg dominic

  • Ich glaub ich weiß was er meint.

    Dazu ein kleines Beispielskript mit Erklärung:

    [autoit]

    Global $iSize, $a[1], $TMP, $RAM

    [/autoit][autoit][/autoit][autoit]

    $iSize = 1024*1024
    ReDim $a[$iSize]

    [/autoit][autoit][/autoit][autoit]

    Sleep(1000)

    [/autoit][autoit][/autoit][autoit]

    For $i = 0 To $iSize - 1 Step 1
    $a[$i] = "a"
    Next

    [/autoit][autoit][/autoit][autoit]

    ToolTip('Fertig')
    Sleep(5000)

    [/autoit]


    Das Array hat 2^20 Elemente.
    Im Taskmanager sieht man (Dafür das Sleep und "Fertig"), dass die RAM-Auslastung ca. 55MB beträgt.
    Wir ziehen davon mal 5MB (um auf der sicheren Seite zu sein) ab um eine Annäherung für den Speicherbedarf des Arrays zu erhalten.
    Also braucht ein Array mit 2^20 Elementen die jeweils nur einen Inhalt von 8Bit haben dennoch einen Speicher von 50MB.
    Das sind pro Element 50 Byte. (Ein "einfaches" Array würde dafür jedoch nur 1 Byte pro Zeichen und 4 Byte für die Längenangabe benötigen.)

    Edit: Hab gerade was interessantes gefunden.
    Wenn man das Array nicht mit "a" sondern mit einem viel längeren String (z.B. "Hallo Leute wie geht es euch ?") füllt bleibt der RAM verbrauch gleich. Selbst wenn dieser String weit über die theoretisch vorhandenen 50 Bytes hinaus geht.
    Ein Array scheint wirklich seltsam aufgebaut zu sein^^

    Der String ist vermutlich in einem Zwischenspeicher und im Array stecken nur die Verweise auf jenen.
    Mit Zufallszahlen geht das nämlich nicht. Dann wird das Array extrem groß.

  • Ich hingegen weiß nicht was er meint.
    Er allokiert Speicher für 1,5 * 10^10 Zeichen.
    Bei Unicode also knapp 28giB Speicher.

    Keine Ahnung warum das ein merkwürdiges Problem von AutoIt sein sollte das zum Speicherüberlauf führt.
    Verwunderlich finde ich hier nichts sondern durchaus logisch.

  • Wie kommt ihr eigentlich auf solch hohe Werte?
    Ich sehe im ersten Post ein Array von 100x100 mit jeweils einem String von 300 Zeichen.

    Ich gehe jetzt mal von 32Bit aus.

    1. Ein Pointer auf das Array = 4 Byte
    2. Das Array mit jeweils einem Pointer auf den String = 100 x 100 x 4 Byte
    3. Die Strings selber mit Unicode = 100 x 100 x 300 x 2 Byte

    Macht bei mir 6040004 Byte => ~5898 Kib => ~5,7 Mib

    Ich gehe zwar davon aus das ein Array in AutoIt durch den Variant Datentyp groeßer ist, aber bei weitem nicht so groß.

  • Lass mal das laufen: Ich weiß jetzt nicht, ob das ein Bug oder ein Feature ist, aber der Variableninhalt wird nicht mehr gelöscht bei der Redeklaration.

    [autoit]

    For $i = 1 To 200
    Local $var
    $var &= "x"
    ConsoleWrite(StringLen($var)
    Next

    [/autoit]
  • Ich sehe im ersten Post ein Array von 100x100 mit jeweils einem String von 300 Zeichen.


    nur im ersten Element sind 300 Zeichen. im 2. sind es schon 600. im 3. dann 900.

    liegt einfach daran dass er die stringvariable nur deklariert und nicht definiert weswegen der Inhalt erhalten bleibt und somit immer länger wird und eine jeweils immer länger werdende Kopie dem array-elementen hinzugefügt wird.

  • Ah danke für die Erklärung.

    Das ist aber ein gewaltiger Bug in AutoIt! :thumbdown: Die Variable ist innerhalb der Schleifen deklariert und dürfte so nie dieses Verhalten zeigen.
    Es müsste eigentlich eine Fehlermeldung kommen, wie "Benutzung einer nicht initialisierten Variable".

  • Das ist aber ein gewaltiger Bug in AutoIt! :thumbdown: Die Variable ist innerhalb der Schleifen deklariert und dürfte so nie dieses Verhalten zeigen.
    Es müsste eigentlich eine Fehlermeldung kommen, wie "Benutzung einer nicht initialisierten Variable".


    Ich finde nicht, dass das ein Fehler in AutoIt ist. Es kann ja auch durchaus mal vorkommen, dass man genau dieses Verhalten mal braucht. Man muss sich halt nur vorher Gedanken darüber machen was passiert, wenn man das so durchlaufen lässt.

  • Ich sehe da auch keinen Bug. Wenn die Variable jetzt auf "" gesetzt werden würde, dann wäre das wohl ein Bug. Aber so? Nein.
    Ich denke eher, dass nach der Deklaration einer Variable, also zum Beispiel Local $var, der Speicher im Prozessor für diese Variable reserviert wird. Wenn man dann also nochmal die Variable deklariert, bringt das rein garnichts, da der Speicher für $var ja schon reserviert worden ist. Nichts passiert.

    So seh' ich das zumindest, und da das Beispiel von Prog@ndy (Nebenbei, du hast eine Klammer vergessen. :rolleyes: ) und meins hier dasselbe Ergebnis erzeugen, fühle ich mich auch bestätigt. :thumbup:

    [autoit]


    Local $var
    For $i = 1 To 200
    $var &= "x"
    ConsoleWrite(StringLen($var) & @CRLF)
    Next

    [/autoit]

    lg chess

  • Naja ich würde es auch nicht direkt als Bug bezeichnen.
    Eher als ein etwas eigenes Verhalten.
    Man muss sich halt klar werden lassen das AutoIt prinzipiell nur 2 Gültigkeitsbereiche kennt: In Funktion und außerhalb von Funktionen.
    Sowas wie in C wo man beliebig per {}-Blöcke kapseln kann gibts hier nicht. Eine Schleife ist daher kein eigener Gültigkeitsbereich.

    Auf der anderen Seite ist die Frage was bei einer Redeklaration ohne Definition passieren soll.
    C z.B. sollte einen Fehler schmeißen weil eine neue Variable erstellt wird welche nicht initialisiert wurde (wenn ich mich recht erinnere).
    In Python z.B. ist hingegen eine Deklaration ohne Definition gar nicht möglich (zumindestens ist mir kein Weg bekannt).
    PHP hingegen verhält sich wie AutoIt (wenn man einen alleinigen Aufruf eines Variablennamens als Deklaration ansieh):

    Code
    $Test = 5;
    $Test;
    echo $Test;

    Das Verhalten kann man also als speziell sprachabhängig ansehen und daher vielleicht eher kaum als Bug.

    Edit: Naja mein Vergleich hinkt ein wenig. Nur $Test in PHP aufzurufen ist in PHP tatsächlich keine Deklaration.
    Interessant wäre vielleicht wie sich andere Sprachen hierbei verhalten.

  • C ist da denk ich kein gutes Beispiel (ich beziehe mich hier auf ANSI-C) weil dort genau das nicht möglich ist. Alle Variablen müssen vor der ersten Anweisung Deklariert werden, weil C innerhalb von Funktionen auch nur einen Gültigkeitsbereich kennt. Es ist dort natürlich auch nicht möglich innerhalb von Schleifen eine Variable zu Deklarieren.

    C schmeißt kein Fehler wenn eine Variable benutzt wird, sie aber nicht initialisiert wurde. In C ist das legal auch wenn es Unsinn ist.

    Alle Sprachen die ich kenne kennen unterschiedliche Gültigkeitsbereiche oder erlauben die Deklaration nur am Anfang einer Funktion.
    Ich finde, das das in AutoIt ein sehr kurioses verhalten ist und würde es nach meiner Ansicht trotzdem als Bug bezeichnen.

  • [..] weil C innerhalb von Funktionen auch nur einen Gültigkeitsbereich kennt. Es ist dort natürlich auch nicht möglich innerhalb von Schleifen eine Variable zu Deklarieren.

    Vermutlich reden wir etwas aneinander vorbei.
    In C kann man per {}-Blöcke auch in Funktionen beliebige Untergültigkeitsbereiche schaffen.
    Also auch in Schleifen.
    Daher führt folgendes Beispiel auch zur Fehlermeldung "error: 'x' undeclared (first use in this function)":

    Spoiler anzeigen

    In der Schleife selbst bleibt die Variable x aber bestehen und wird problemlos weiter inkrementiert.

    C schmeißt kein Fehler wenn eine Variable benutzt wird, sie aber nicht initialisiert wurde. In C ist das legal auch wenn es Unsinn ist.

    Habs grad nochmal getestet - du hast Recht - wirft tatsächlich keinen Fehler sondern nur eine Warnung.

  • Hehe, nene wie reden nicht aneinander vorbei.

    In C89 (ANSI-C), und C90 müssen alle Variablen am Anfang der Funktion deklariert werden.
    Das Bespiel von dir geht nur mit C99. Erst dieser Standard kennt Untergültigkeitsbereiche.

    In C89 und C90 müsste der Code so geschrieben werden.

  • Hei cool


    Viele antworten hier. Recht ineressant.


    Kenn mich mit speicher zuweisung uns was hald dazugehört nicht aus.
    Meinen fehler hab ich ja gleich gefunden, wunderte mich nur dass das soviel speiche benötigt das wars :)

    mfg

  • Dazu muss man sagen, dass AutoIt immer ein paar Byte zusätzlich alloziiert, damit noch Platz für weitere Zeichen ist und nicht beim Anhängen z.B. eines weiteren Zeichens gleich neuer Speicher alloziiert werden muss.

    EDIT:

    Lass mal das laufen: Ich weiß jetzt nicht, ob das ein Bug oder ein Feature ist, aber der Variableninhalt wird nicht mehr gelöscht bei der Redeklaration.

    [autoit]

    For $i = 1 To 200
    Local $var
    $var &= "x"
    ConsoleWrite(StringLen($var)
    Next

    [/autoit]

    Das ist ein Feature und wird im Manual erwähnt bei "Language Reference">"Variables">"Scope". Es gibt nur den zwei scopes: Global und in Funktionen, während bei anderen Programmiersprachen oft jeder Block einen eigenen scope hat.
    Ich finde das ungünstig, denn es ist eine zusätzliche Fehlerquelle, da man in Funktionen globale Variablen deklarieren kann, und man außerhalb der Funktion nicht sicher sein kann, ob die Variable überhaupt existiert.

    Außnahme von der Regelung sind die Laufvariablen von for-loops.

  • Entschuldige, jetzt bin ich verwirrt. Was findest du jetzt ungünstig?

    Das AutoIt nur zwei Gültigkeitsbereiche kennt, das globale Variablen innerhalb einer Funktion deklariert werden können, das Lokale Variablen bspw. in Schleifen deklariert werden können und danach weiter existieren oder das andere Sprachen mehr als zwei Gültigkeitsbereiche kennen?

    Meine Meinung über globale Variablen in Funktionen und das Problem mit dem deklarieren von lokalen Variablen in Funktionen dürfte denk ich klar sein.
    Das mit zwei Scopes ist ja nicht mein Problem, nur die Umsetzung ist misst.

    „AutoIt immer ein paar Byte zusätzlich alloziiert“ woher hast du eigentlich die Information?
    Das würde mich wirklich interessieren ob sie das wirklich so machen, da gibt es nämlich viele unterschiedliche Herangehensweisen was Strings betrifft.