Dieter Strassner <
spam...@strassner.biz> schrieb im Beitrag
<j8ts60$vij$
1...@news.albasani.net>...
> Am Hauptspeicher kann es hier auf meinem PC nicht liegen, der PC hat 3GB,
> davon maximal 600MB in Benutzung (während die Fehlermeldung 14 angezeigt
> wird).
Das Problem dürfte weniger dadurch verursacht sein, daß nicht genügend
Speicher zur Verfügung steht, sondern daß nicht genügend
_zusammenhängender_ Speicher zur Verfügung steht. Wenn es unter dem einen
OS früher auftritt als unter dem anderen, dürfte das daraufhindeuten, daß
das andere OS eine effizientere Speicherverwaltung verwendet.
Für Fragmentierung gibt es jede Menge Ursachen; das fängt dort an, wo das
OS verwendete DLLs etc. in den Speicher des Prozesses mappt; und es hört
nicht bei der simplen Zusammensetzung von Strings in VB auf, denn Du mußt
bedenken, daß VB für jeden String nicht nur den eigentlichen
String-Speicher allozieren muß sondern auch noch Speicher für den
String-Pointer (String = Pointer auf Pointer auf String); letzteres
benötigt zwar nicht viel Speicher, aber jeder allozierte Speicher kann
verhindern, daß Speicher fragmentiert wird.
Das Hauptproblem ist natürlich, daß der allozierte Speicher bei der
Zuweisung von Strings unter VB auch mit SysReAllocString() erst freigegeben
wird, _nachdem_ der neue Speicher alloziert wurde.
Eine mögliche Problemlösung wäre, in Deiner Klasse eine eigene
String-Speicherverwaltung mit LocalAlloc(), LocalReAlloc() etc. aufzubauen.
LocalReAlloc() wie auch GlobalReAlloc() versuchen m.W. erst, den bereits
allozierten Speicher zu erweitern; nur, wenn das fehlschlägt, wird neuer
Speicher alloziert und der alte Speicherinhalt umkopiert - was auch für die
Performance interessant wäre.
Eine andere übliche Methode ist, den String nicht bei jeder Änderung neu
zusammenzusetzen sondern mit voralloziertem Speicher zu arbeiten, d.h. es
wird seltener neu alloziert, dafür aber mehr Speicher am Stück, wodurch die
Fragmentierung - je nach Größe des vorallozierten Speichers - erheblich
sinken und die Geschwindigkeit deutlich steigen kann. Deine Klasse muß dann
natürlich eine zusätzliche String-Längenangabe verwalten. Schematisches
Beispiel ('on-the-fly'):
Const ALLOCSIZE As Long = ...
sClassMem = String$(ALLOCSIZE, vbNullChar)
lClassMemUsed = 0
...
lLen = Len(sStringToAdd)
If (lClassMemUsed + lLen) > Len(sClassMem) Then
lCount = lLen - (Len(sClassMem) - lClassMemUsed)
If lCount < ALLOCSIZE Then lCount = ALLOCSIZE
sClassMem = sClassMem & String$(lCount, vbNullChar)
' **
End If
Mid$(sClassMem, lClassMemUsed + 1) = sStringToAdd
lClassMemUsed = lClassMemUsed + lLen
Mid$() = <String> hat dabei den häufig übersehenen Vorteil, daß _kein_
neuer Speicher alloziert sondern <String> in den bereits allozierte kopiert
wird.
An der mit '**' bezeichneten Stelle kann man dann noch einen zusätzlichen
Schutz einbauen:
Tritt hier einer der 'Out of memory'-Fehler auf, schreibt man den gesamten
String in eine temporäre Datei (dann natürlich mit Windows API-Methoden),
löscht den _gesamten_ Klassen-Speicher (und räumt möglw. auch sonst noch
auf), alloziert ihn neu in der erforderlichen Größe (+ Zusatz) und liest
den String wieder ein. Kommt es auch dabei zu einem der 'Out of
memory'-Fehler, muß man sich eine andere Strategie überlegen...
Sollte sich das Problem so nicht lösen lassen, wäre vielleicht DDE eine
Lösung, um den String in Word zu übertragen. Auch eine Übergabe über die
Zwischenablage könnte eine Lösung sein.
--
Thorsten Albers
gudea at
gmx.de