Entwickler-Ecke
Algorithmen, Optimierung und Assembler - Strings "kopieren"
Heiko - Fr 14.07.06 12:37
Titel: Strings "kopieren"
Hallo,
ich habe einen String und möchte den kopieren, allerdings mit GetMem etc., da ich den Zeiger brauch und der String sonst überschreiben wird ;).
Nun ja, wie kopiert man es am besten (ohne ASM)?
Ich habs momentan so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| s: WideString; len: integer; s:='test'; len:=length(s)*2+2; GetMem(p, len); Move(s[1], p, len); |
Mich würde vor allem interessieren, wie man die Längenbestimmung optimieren kann, denn das ist noch nicht das gelbe vom Ei :cry: .
Motzi - Fr 14.07.06 12:55
Ganz einfach.. ;)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| var s: String; s2: String; s := 'test'; s2 := s; UniqueString(s2); |
Gruß, Motzi
Edit: ich seh grad erst, dass du ja mit einem WideString arbeitest. In diesem Fall reicht eine einfache Zuweisung an die Variable die die Kopie enthalten soll - WideStrings haben keine Referenzzählung und sind immer unique!
Heiko - Fr 14.07.06 13:04
Gut zu wissen :). Aber leider ist es nicht ganz die Lösung meines Problems. Und zwar bringen mir zusätzliche Variablen nichts, da ich vorher nicht weiß, wieviel ich brauchen werde. Ich wollte mir jetzt immer nur die Zeiger auf die Strings speichern, sprich statt einer Variable dauernd den WideString zu übergeben, und damit den alten Inhalt zu löschen, brauche ich eben etwas, womit immer ein neuer Speicherbereich verwendet wird.
Motzi - Fr 14.07.06 13:05
Sorry, das versteh ich nicht ganz.. erklär nochmal genauer und vielleicht auch mit dem Hintergrund warum du das so machen willst. Vielleicht findet sich eine andere/bessere Lösung.
Heiko - Fr 14.07.06 13:44
Und zwar geht es um meine Unit
SearchTool [
http://www.delphi-forum.de/topic_SearchTool++schnelles+Suchverfahren_48936.html] (Festplatte nach Dateien durchsuchen). Ich will jetzt probieren aus dem rekusiven Verfahren ein iteratives zu machen (ob es Performancevorteile ergibt, da keine "sinnlosen" Stufen entstehen). Um das zu realisieren reserviere ich mir immer 104 Bytes. Die ersten 100 Byte sind als Platzhalter für 25 Pointer auf die WideStrings gedacht und die letzten 4 Bytes für einen Pointer auf das nächste "104er-Element" (du weißt was ich meine ;) ). Das war es erst einmal zur "Speicherverwaltung".
Nun zum Suchalgorithmus. Die 104er-Elemente werden erst einmal auf 0en "resetet" (mit ZeroMemory). Wenn der Suchalgo nun einen Ordner findet, fügt er den Zeiger von dem WideString dem Element hinzu (der nächste gefundene Ordner nimmt dann die nächsten 4 Bytes etc. Und sobald die 25 Ordner voll sind, reserviert er sich ein neues Element und fängt dort wieder von vorne mit dem befüllen fort). Und diese Ordner durchsucht er nach und nach.
So das wäre das wichtigste zum Verfahren. Also das Problem, um das es hier geht, ist das im Zweiten Absatz beschriebene.
Motzi - Fr 14.07.06 13:58
Ok.. dann würde ich zu den APIs SysAllocString und SysFreeString raten...
Heiko - Fr 14.07.06 14:05
In welcher Unit sind die? (Delphi findet die nicht, aber auch in der Delphi-Hilfe sind sie nicht enthalten :( )
Motzi - Fr 14.07.06 14:16
Das sind Windows-APIs, die wirst du nicht in der Delphi-Hilfe finden. Die Dokumentation findest du im MSDN:
SYSALLOCSTRING
SYSFREESTRING
Die beiden Funktionen sind in der Unit "ActiveX" definiert.
Heiko - Fr 14.07.06 14:21
Ahh k, thx (da hatte ichs ja nur in der anderen Unit ausprobieren müssen, da dort ActiveX automatisch dabei ist ;) ). Ich probiers jetzzt mal aus, obs so funzt, wie ichs will
Heiko - So 23.07.06 14:47
Hallo Motzi,
ich bin jetzt soweit, das ich die beiden Befehele benötige. SysAllocString funktioniert so, wie ichs brauch, aber SysFreeString funktioniert irgendwie nicht, was ich seltsam finde. Muss ich da etwas zusätzliches beachten?
Motzi - So 23.07.06 14:52
Was genau meinst du mit "funktioniert nicht"?
Heiko - So 23.07.06 15:23
Nun ja, über SysAllocString werden ca. 42 MB (wovon ich selber per GetMem nur 376 KB reserviere, der rest also auf SysAllocMem geht) reserviert, und er dann nichts wirklich freigibt, obwohl er die Freigebe-Routine durchläuft. Er geht am Ende ca. 1 MB nur wieder nach unten, und das müsste der Teil sein, den ich selber per GetMem reserviert hatte (also die 376 KB). Erst wenn das Programm beendet wird, wird der RAM freigegeben (vermutlich von Windows, der den datenmüll erkennt ;) ).
PS: Die zahlen waren nur auf die Auslagerungsdateien bezogen. Im Physikalischen Speicher verhält es sich so ähnlich ;).
Motzi - So 23.07.06 17:41
Es ist oft so, dass der reservierte Speicher zwar freigegeben wird, dies aber nicht immer sofort angezeigt wird (zB im Taskmanager). Versuch mal was passiert wenn du das Programm minimiertst. Oft zeigt der Taskmanager dann auf einmal schlagartig nur mehr einen Bruchteil der Speicherauslastung an...
Heiko - So 23.07.06 17:48
Mhm, das bringt leider auch keine Änderung. Ich ahbe mal den Code soweit abgespeckt, dass du keine extra Kompos brauchst, um dir mal den soucre anzusehen und aus zu probieren ;).
PS: Mich wundert es gerade, dass in der abgespeckten Version noch ein Systemerror kommt, ka wieso :(. (Erst ab dem 2. Durchlauf)
Motzi - So 23.07.06 18:51
Muss es mir erst genauer anschaun, aber auf den ersten Blick gibt es einige Dinge die mir ganz und gar nicht gefallen (vor allem im Bezug auf den Thread)..!
Heiko - So 23.07.06 19:51
Motzi hat folgendes geschrieben: |
vor allem im Bezug auf den Thread..! |
Nun ja, ich arbeite normalerweise mit der Klasse TThread und nicht mit BeginThread etc. ;), und wie gesagt, ich habe einiges weggenommen in der Demo, damit du nur das nötigste hast. Ich hasse es nur an Threads, das man auf Komponenten eigentlich überhaupt nicht zugreifen darf, ich es aber meistens doch mache, wiel ich kein Bog habe immer alles über Synchronisation oder Messages zu machen (ich bevorzuge Messages ;) ).
Motzi - Mo 24.07.06 15:30
Ich hab mal deinen Code komplett überarbeitet und dir einen Thread direkt in die Klasse eingebaut.. ;) Schaus dir mal an wenn falls du noch Fragen dazu hast zöger nicht..! :)
Gruß, Motzi
Heiko - Mo 24.07.06 17:10
k, erst einmal danke, dass du für mein Problem dir Zeit genommen hast :zustimm: .
Bei den Thread sachen muss ich erst einmal gucken, was vereinzelte Befehele genau machen (dadurch das ich in bestimmten Bereichen die Fehlerwahrscheinlich für extrem gering halte, habe ich mich da eben nicht drum gekümmert ;) ).
Aber eine kleine Frage zu Threads allegmein habe ich dennoch. Wenn 2 verschiedene Threads gleichzeitig auf einen Pointer zugreifen, der eine liest (kann damit ja keinen Schaden anrichten) und der andere schreibt (beim schreiben kann es ja zu Fehlern im 1. Thread kommen, da er ja gleichzeitig liest), tritt das Problem erst auf, wenn mehr als 4 Bytes geändert werden, oder kann es passieren, dass der eine dann eine Mischung der beiden Pointer hat (z.B. die ersten beiden Bytes neu und die anderen beiden noch alt)? Das bei größeren Strukturen ein Problem besteht ist mir klar, nur eben bei den 4 Bytes nicht, da ja der Processor mit 32-Bit arbeitet, also ob er auch immer 4-Byte-weise schreibt.
@Zeigern: Ist GetMemory haargenau das gleiche wie GetMem, nur dass bei dem einen der Output als Paramater ist, und der andere als Funktionsrückgabe (die Delphihilfe von D2005 schweigt leider im Index über diese Befehle :bawling: )?
Und das ich an einigen Stellen das ^ hinter der Variable vergessne hatte, leigt einfach daran, dass ich mir das mit den Zeigern zwangslaufig alleine erarbeitet hatte (wir sind auf VirtualStringTree umgestiegen, wo das meiste mit Zeigern ist, und man eben ein ganz kleines bissl davon braucht), dadurch fehlen mir noch vereinzeltes Grundwissen zu Zeigern (Var^ war eigentlich die einzigste Variante, die ich nicht kannt, denn ansonsten gibt es ja meines Wissens nach nur noch @ und ^Typ ;) ). (Und was Zeiger sind etc. weiß ich ja so ;) ).
@Das eigentliche Problem: Nun ja, leider bringt dein Code auch keine Speicherfreigabe :(. Von dem was ich so gesehen habe, läuft es ja immer noch so ab, wie ichs hatte.
PS: Die Freigabe, so wie du es umgestaltet hast, dürfte langsamer sein, als die die ich hatte ;). Ich habe eben gewisse Überprüfungen weggelassen, da SysFreeString(0) nichts macht (laut MSDN), von daher ist die Überprüfung auf o (nil) unnötig.
Ecki - Mo 18.09.06 21:43
Hallo,
ich versteh dein Problem zwar nicht ganz, aber nach meiner Erfahrung tun es die dynamischen Array´s von Delphi ganz gut. Ich verwende einfach Array of String. Wenn du Platz benötigtst, dann schreib einfach
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| var sa: array of string; begin ...
if i>high(sa) then Setlength(sa, high(sa)+1000)
sa[i] := ... |
und wenn Du fertig bist:
Damit werden immer Blöcke z.B. von 1000 reserviert. Das kann man noch ein bischen schöner schreiben, aber so gehts. Deine Pointerverwaltung braucht ja auch was Zeit, und ich würde die Sachen einfach mal in einer Schleife gegeneinander vergleichen. Manchmal ist das schon überraschend...
Ist natürlich keine Garantie, das es schneller ist.
Meistens liegt das Problem sowieso in unnötigen String-Zuweisungen oder Konvertierungen. Setz mal einen Breakpoint in deine Routine und schau Dir das CPU-Fenster an. Der Assembler-Coder mag vielleicht nicht gut lesbar sein, aber unnötige Aufrufe findest Du schon.
Gruß, Ecki
Moderiert von
Christian S.: Delphi-Tags hinzugefügt
alzaimar - Mo 18.09.06 22:38
Hi Heiko,
Wenn Du dein Stringproblem in einem kleinen Beispielcode packen kannst, dann können wir gemeinsam eine performantere Lösung suchen. Damit meine ich nicht deine Demo, sondern ein kleines Testprogramm, das deine Widestring-Datenstrukutr beinhaltet.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!