• Bitte schaltet eure Ad Blocker aus. SLinfo kann nur betrieben werden, wenn es durch Werbung Einnahmen erzielt. Vielen Dank!!
  • Wir freuen uns, wenn du dich in unserem Forum anmeldest. Bitte beachte, dass die Freigabe per Hand durchgeführt wird (Schutz vor Spammer). Damit kann die Freigabe bis zu 24 Stunden dauern.
  • Wir verwenden Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und die Zugriffe auf unsere Website zu analysieren. Sie geben Einwilligung zu unseren Cookies, wenn Sie unsere Webseite weiterhin nutzen.

"Seiteneffekte" bei String-Speicherverwaltung bekannt ?

Ich bevorzuge Listen-Verwaltung, gerade weil ich mir dann um die laenge der Strings nicht sonderlich viel Gedanken machen muss.
Zum Thema Speicher habe ich ne grobe Faustregel, "FreeMemory / 100 = moegliche Anzahl Listeneintraege". Ich rechne immer in Keys, weil ein einfaches Script etwa 600 UUIDs in einer globalen Liste speichern kann (reduziert sich natuerlich mit jedem zusaetzlichen Code im Script). Dennoch fahre ich mit der Faustregel ganz gut, weil die UUIDs im Grunde den meisten Speicher verbrauchen und ich dann jede Menge reserven habe, wenn ich eben keine UUIDs sondern Integer, Vectoren oder sonst was speichere. Eine Ausnahme stellen Texte dar, weil der Speicher von der laenge abhaengig ist.

Im Grossen und Ganzen komme ich mit Listen besser zurecht als mit Strings zerpfluecken.
Solche sachen wie llGetSubString, llDeleteSubString und Co verwende ich nur fuer kosmetische zwecke (Hovertext, Chatmeldungen und XYZ-Text).

LG
Dae
 
Zuletzt bearbeitet:
Eine Übersicht wie viel Speicher was belegt gibts hier:
http://wiki.secondlife.com/wiki/LSL_Script_Memory, allerdings hängt die exakte Belegung letztendlich auch noch vom Code, da kann möglicherweise der Compiler z.B. bestimmte Funktionen direkt in den Code einbauen usw. Oder überflüssige Variablen rauswerfen.

Was allerdings leider immer viel Speicher braucht: Funktionen, die mit Listen und Strings arbeiten.
Das liegt daran, dass diese Funktionen wie z.B. llListInsertList oder llGetSubString usw.wohl leider intern gern erst mal temporäre Kopien des Stings anlegen. So dass man auch dann, wenn man eigentlich viele Keys in eine List kriegt, nur bedingt mit wirklich extrem langen Listen arbeiten kann.

Trotzdem sollten eigentlich weder bei Listen noch bei Strings derartige seltsame Probleme auftreten, bei denen zufällige Werte ausgegeben werden.
Wenn es da einen internen Speicherkonflikt gibt und ein Zeiger in einer Liste oder einem String (ich nehme mal an dass es damit realisiert wird intern) auf eine Speicherzelle verweist, die nicht zum Programm gehört, dann müsste das Script eigentlich von der VM mit einem Segmentation fault angehalten werden, so wie es auch künstlich angehalten wird (und einen Stack/Heap collision Fehler zurückmeldet), wenn ein Script bei einer der internen Stopmarken immer noch mehr als die erlaubten 64kB hat. Und selbst wenn es das nicht tut müsse eigentlich der Mono Garbage Collector dann über diesen Zugriff stolpern.
 
Thema Listen vs. String: Wir hatten ja schon einmal einen Thread dazu. Listen scheinen
weniger effektiv im Speicher verarbeitet zu werden, als es bei Strings der Fall ist. Innerhalb
LSL scheint es eher zur Speicherfragmentierung zu kommen, wenn Listen im Spiel
sind.

Listen sind bequem und ich würde sie gerne öfter einsetzen. Aber ich bin misstrauisch
und gehe mit Strings den sichereren Weg. Immer dort, wo viel und sehr lange an einem
Stück (also ohne zwischenzeitlichen Reset) zugegriffen werden muss.

Bei gleichgrossen Offsetabständen ist das simpel.
 
Das Problem ist gelöst ! Zum Glück hatte ich nur einen virtuellen Bierkasten
gewettet.

Hier steht er: "KASTEN BIER" :mrgreen:


Es war doch mein Fehler:

Ich scanne ein Array und teste auf eine bestimmte Bedingung. Werde ich fündig,
geht es damit in den nächsten Test auf eine weitere Bedingung. In einer früheren
Version brach ich dann komplett ab. In der neuen Version macht das keinen Sinn und führt
zu dem seltsamen Verhalten.

Ich hatte schlicht vergessen, das "return" aus der Schleife herauszunehmen.

Ist das Array noch fast leer, und werden zufällig keine Daten vor dem Scan relevanter Stellen
gefunden, läuft es wie es soll. Füllt sich das Array aber mit der Zeit, lassen die Daten, die
nur die erste Bedingung, aber nicht die zweite Bedingung erfüllen, die Scanfunktion abbrechen..

oehm...

;-)
 
Thema Listen vs. String: Wir hatten ja schon einmal einen Thread dazu. Listen scheinen
weniger effektiv im Speicher verarbeitet zu werden, als es bei Strings der Fall ist. Innerhalb
LSL scheint es eher zur Speicherfragmentierung zu kommen, wenn Listen im Spiel
sind.



Listen sind bequem und ich würde sie gerne öfter einsetzen. Aber ich bin misstrauisch
und gehe mit Strings den sichereren Weg. Immer dort, wo viel und sehr lange an einem
Stück (also ohne zwischenzeitlichen Reset) zugegriffen werden muss.

Bei gleichgrossen Offsetabständen ist das simpel.

Listen brauchen manchmal mehr Speicher als Strings, das ist schon richtig. Das liegt daran, dass eben zusätzlich zu den in den Listen abgespeicherten Daten noch die Metadaten der Liste gespeichert werden müssen. Normale Strings dagegen sind im Grunde einfach ein kurzer "Meta-Kopf" und dann einfach verkettete Chars (also letztendlich einfach Zahlen zwischen 0 und 256), die damit jeweils weitere 1byte belegen. Und allenfalls noch ein Zero-Byte als Endmarker.

Beispiel:
Ein 4-Tupel aus 1.001, 1.002, 1.003 und 1.004 kann auf viele verschiedene Arten im Script gespeichert werden. Z.B. im default state als lokale Variable.
Als String sind das 23 Chars, also braucht das ganze 12 byte + 23 byte, also 35 Byte.
Speichert man das in eine Liste sind das 4 floats, die da gespeichert werden müssen, braucht es mehr speicher:
15 byte + (4 x 7byte) = 43 Byte.
Als rotation gespeichert braucht es 39 Byte.


Dafür ist allerdings der Zugriff auf diese Werte dann wiederum ganz unterschiedlich.
Auf Komponenten von Rotationen kann man mit .x .y .z und .s absolut unkompliziert zugreifen (genau wie auch auf Vektoren), da dort einfach floats liegen. Man braucht also nicht mal ein Typecasting.

Der Zugriff auf Listen ist bisschen komplizierter, mit llList2Float braucht man schon eine Funktion dafür, die für jeden Float aufgerufen werden muss.

Mit Strings ist das dann wiederum noch mal komplizierter - hier braucht man dann ein typecasting um aus dem string Floats zu machen. Davor muss allerdings der jeweilige Float aus dem String ausgeschnitten werden - weswegen man den String leider parsen muss, wenn man keine fix formatierten floats speichert. D.h. man muss da den Anfang des Floats finden, den Punkt im Float und dann noch die zugehörigen Nachkommastellen. Einfach weil ein Float ja z.B. 100.03 sein kann oder 1.002 oder 1.04 - oder wie auch immer. Eine Abhilfe hier ist das Arbeiten mit CSV oder besser JSON - aber auch damit ist das Ganze leider immer noch mit mehreren Schritten und Funktionen verbunden.

Da aber jeder Schritt mit einem potenziellen Fehler verbunden ist und auch Rechenzeit kostet halte ich selbst es meist "möglichst einfach". Und setze z.B. gerne Vektoren und Rotationen für Float-Tupel ein, da man auf diese super einfach zugreifen kann. Und sie trotzdem z.B. noch in Strided Lists verarbeiten kann usw.

Ansonsten arbeite ich wenn möglich auch mit Listen, da man mit diesen einfach ziemlich viel machen kann. Und da man aus diesen die Werte ohne Typecasting und loops sehr einfach raus kriegt (was ja auch wieder Speicher und Rechenzeit kostet).

Strings verwende ich eigentlich nur dann, wenn ich wirklich mit Strings arbeiten muss, etwa für die Ausgabe oder die Eingabe per Listener. Denn wenn man auf bestimmte Elemente zugreifen will, dann geht das eben nicht einfach mit einem Index ohne weiteres, man muss da dann schon vorher genau wissen aus wie vielen Chars ein Float z.B. besteht, einfach "Hol mir den Float an Index 3" reicht da nicht. Man muss dann schon wissen wie viele Digits das in der Zahl sind. Und sollte man sich mit dem Index vertun, dann spuckt das Programm nicht mal einen Fehler aus und läuft einfach weiter, was eine massive Fehlerquelle ist.

Und zum Speicher selbst:
Speicherfragmentiereung ist unter Mono in SL kein Thema mehr, da sind Scripte generell kein zusammenhängender Speicherbereich mehr wie noch unter LSO, der Speicher wird dynamisch und generell fragmentiert belegt. Und Scripte können so nicht nur (zumindest kurz, solange kein Stopcode kommt....) mehr als 64kB belegen, sondern beherrschen eben auch Bytecode sharing. D.h. Kopien von kompilierten Scripten auf dem selben Server belegen so für viele Funktionen und Konstanten usw. keinen eigenen Speicher mehr sondern verweisen auf ein bereits in den Speicher geladenes script. So dass für Kopien von Scripten im Wesentlichen nur noch die Speicherbereiche, die sich im Ablauf verändern können, neu belegt werden müssen. Wird allerdings ein Script nicht kopiert sondern auch noch neu kompiliert, dann geht das nicht mehr.
 
Und zum Speicher selbst:
Speicherfragmentiereung ist unter Mono in SL kein Thema mehr, da sind Scripte generell kein zusammenhängender Speicherbereich mehr

Ich hatte einmal ein paar Tests durchgeführt, die nach ein paar Listenoperationen (mit immer denselben Daten) zunehmend
Speicher belegten. Daraus schloss ich, das es eben doch Fragmentierung gibt. Auslöser meiner Bedenken war, als vor längerer
Zeit in einem Script sporadisch Heap-Überläufe vorkamen, wobei die Datenmenge nicht kritisch wurde. Seitdem verfahre ich so:

1. Sind String-Methoden sicher genug (auch im Sinne der Wartung bei Weiterentwicklungen), dann wähle ich diese.
Geschwindigkeitsnachteile wären auch ein Kriterium; aber da stelle ich bislang nichts negatives fest.

2. Bieten sich Listen "allzusehr" an, benutze ich sie. Sind dabei aber grössere Datenbewegungen im Spiel, verteile ich die
Listen-"Technik" in einzelne Scripts, die dann sozusagen als "ferngesteuerte" Speicher arbeiten. Sie enthalten dann ein
Minimum an Verwaltung, die per linkedmessage ihre Kommandos erhalten: Schreiben / Ersetzen / Lesen / Löschen und evtl.
noch sortierte Ausgabe. Das jeweilige Speicher-Script hat dann immer einen ausreichend grossen Speicher zur Verfügung,
weil ich bei Bedarf weitere solcher Speichereinheiten hinzufügen kann.
 
Zuletzt bearbeitet:

Users who are viewing this thread

Zurück
Oben Unten