VB6: Arbeitsspeicher-'Verbrauch'

Hallo zusammen.

Ich würde gerne wissen, ob (z.B.) 100 einzeln deklarierte Variablen verschiendener Datentypen mehr Arbeitsspeicher „verbrauchen“ als ein einziges als Variant deklariertes Datenfeld mit 100 Datensätzen.

Weiß einer was?

VG
Carsten

Hallo Carsten,

in der Hilfe gefunden:

‚Ein Wert vom Typ Variant nimmt immer 16 Byte ein, unabhängig davon, was Sie darin speichern.‘

Byte = 1 Byte
Integer = 2 Bytes
Long = 4 Bytes
Single = 4 Bytes
Double = 8 Bytes

Kein Unterschied besteht also nur bei Strings.

Gruß Rainer

Ich würde gerne wissen, ob (z.B.) 100 einzeln deklarierte
Variablen verschiendener Datentypen mehr Arbeitsspeicher
„verbrauchen“ als ein einziges als Variant deklariertes
Datenfeld mit 100 Datensätzen.

Hi Carsten,

so Dinge haben mich auch schon beschäftigt, leider kam ich Excxel-Vba nicht auf die Schliche wie ich da den reservierten Arbeitsspeicher für Excel „überwachen“ kann.

Starte Test und variiere die „9“ und den Datentyp von a().
Wie du sehen wirst, ändert sich an den Ergebnissen in den Zellen nix.
Als ob man den falschen Speicherbereich checkt oder vor der Laufzeit der Codes schon der Platz reserviert wäre.

Ich weiß zwar, alle DIMs werden vor bzw. anfangs der Laufzeit kompiliert, aber das gilt doch wohl nur für eine Prozedur und nicht für alle Prozeduren in einem Modul/Projekt!?

Ist jetzt Exce-Vba, muß jetzt weg, teste das aber nachher mit VB5.

Sub test()
Range("A1") = Application.MemoryFree
Range("A2") = Application.MemoryUsed
Range("A3") = Application.MemoryTotal
Call Platz
End Sub

Sub Platz()
Dim N, a(9) As Variant
For N = 0 To Ubound(a)
 a(N) = N \* 10
Next N
Range("B1") = Application.MemoryFree
Range("B2") = Application.MemoryUsed
Range("B3") = Application.MemoryTotal
End Sub

Gruß
Reinhard

Hallo Rainer.

Wenn das bedeutet, daß ich dann sowohl für ein Variant-Datenfeld mit 100 Datensätzen, als auch für eines mit 10000 Datensätzen nur 16 Bytes benötige, dann hab’ ich wohl endlich 'mal die richtige Wahl getroffen.

Dann muß ich ja nur noch die „Jugendsünden“ in meinem Code beseitigen. Ooooh, mein Gott.

Danke

VG
Carsten

Hallo Reinhard.

Vielleicht werden ja solche lokalen Variablen gar nicht im „Application.MemoryUsed“ gespeichtert.

Ich speichere für meine Software, die ich schreibe (bitte nichts Großartiges drunter vorstellen), die notwendigen Daten in Daten-Dateien (ich mag GetSetting und SaveSetting irgendwie nicht, weil ich keine Vorstellung davon habe, wo dann meine Daten abgeblieben sind).

Wenn ich nun die Anwendung starte, werden die Daten aus diesen Dateien gelesen, in ein Variant-Datenfeld geschrieben und stehen quasi während der gesamten Laufzeit permanent zur Verfügung. Und hier stellt sich dann die Frage, ob das überhaupt notwendig ist und wieviel Arbeitsspeicher ich dann damit belege.

VG
Carsten

Hallo Carsten,

Wenn das bedeutet, daß ich dann sowohl für ein Variant-Datenfeld
mit 100 Datensätzen, als auch für eines mit 10000 Datensätzen nur
16 Bytes benötige, dann hab’ ich wohl endlich 'mal die richtige
Wahl getroffen.

Nein, bedeutet das nicht. :smile: Pro Variable natürlich.

Ein Array … Arr(1 To 100) As Integer … verbraucht 200 Bytes,
Ein Array … Arr(1 To 100) As Variant … verbraucht 1600 Bytes.

100 mal so viele Variablen benötigen natürlich auch 100 mal so viel Platz.

Was ich nur nicht verstehe ist, warum Du von ‚Datensätzen‘ sprichst. Ich denke an Arrays, Datensatz bringe ich eher mit Datenbanken in Verbindung. Da käme es dann darauf an, welche Datenbank gemeint ist.

Aber egal welche Datenbank, der Platzbedarf ist deutlich größer und so einfach nicht zu berechnen. Um da schnelle Zugriffe zu ermöglichen müssen die Daten mehrfach gespeichert werden. Einmal die Datensätze selbst, dann zusammen mit Zeigern noch einmal die relevanten Teile als Schlüssel und das jeweils mit relativ viel Platzverschwendung, um die Verwaltung zu beschleunigen.

Je moderner die Datenbank ist, um so mehr Speicher belegt sie schon ohne Daten.

Gruß Rainer

Hallo Rainer,

Nein, bedeutet das nicht. :smile: Pro Variable natürlich.

Ein Array … Arr(1 To 100) As Integer … verbraucht 200
Bytes,
Ein Array … Arr(1 To 100) As Variant … verbraucht 1600
Bytes.

Die Rechnung stimmt so nicht ganz, da kommen noch ein paar Bytes dazu.
Ich bin gerade zu Faul um die genauen Werte rauszusuchen.
Es gibt einen Eintrag für die Variable selbst, dieser Enthält den Datentyp, Die Werte für den unteren und oberen IndexWert.

Es gilt also:
X + Anzahl Einträge * BytesProEintrag

MfG Peter(TOO)

Hallo Reinhard,

so Dinge haben mich auch schon beschäftigt, leider kam ich
Excxel-Vba nicht auf die Schliche wie ich da den reservierten
Arbeitsspeicher für Excel „überwachen“ kann.

VBA ist eine Interpreter, das braucht auch noch Platz für den Variablennamen.

MfG Peter(TOO)

Hallo Carsten,

Vielleicht werden ja solche lokalen Variablen gar nicht im
„Application.MemoryUsed“ gespeichtert.

Von VB fand ich jetzt nichtsm das hier gilt für Excel Vba:
http://www.xlam.ch/xlimits/speicher.htm#Die%20sechs%…

Aber dies hier ist für VB. Variant ist unterschiedlich lang, je nachdem ob Zahlen (Double?) drin sthene oder Strings.
Wenn man den Code umschreibt kommt man sicher daran was da wie im Speicher steht.

http://www.spotlight-data.de/lisp/pages/messages/amv…

Ich speichere für meine Software, die ich schreibe (bitte
nichts Großartiges drunter vorstellen), die notwendigen Daten
in Daten-Dateien (ich mag GetSetting und SaveSetting irgendwie
nicht, weil ich keine Vorstellung davon habe, wo dann meine
Daten abgeblieben sind).

? In der Registry. Schreib halt mit Savesetting was außergewöhnliches rein, „xyz#+zt“ o.ä. und such danch in der Registry.
Soweit ich weiß bilden zwei Dateien die Registry, User.dat und system.dat.

Windows reagiert sehr sensibel bzw. knallhart wenn man da einen Fehler macht.

Gruß
Reinhard

Nachtrag
Hallo Rainer,

Ich bin gerade zu Faul um die genauen Werte rauszusuchen.

Ich war doch nicht zu faul :wink:

Es gibt einen Eintrag für die Variable selbst, dieser Enthält
den Datentyp, Die Werte für den unteren und oberen IndexWert.

Es gilt also:
X + Anzahl Einträge * BytesProEintrag

Es sind 20 Bytes für das Array.
Zusätzlich noch 4 byte für jede Dimension des Arrays.
Also

20 + 4 * AnzahlDimensionen + Anzahl DatenElement * BytesProElement

MfG Peter(TOO)

1 Like

Hallo Peter,

danke! So präzise wußte ich das nicht. Ich war schon stolz, daß ich es geschafft habe, ein Stringarray mit CopyMemory sehr schnell zu sortieren. :smile:

Gruß Rainer

Hallo Rainer.

Nein, bedeutet das nicht. :smile: Pro Variable natürlich.

Na, so’n Ärger :smile:

Was ich nur nicht verstehe ist, warum Du von ‚Datensätzen‘
sprichst. Ich denke an Arrays, Datensatz bringe ich eher mit
Datenbanken in Verbindung. Da käme es dann darauf an, welche
Datenbank gemeint ist.

Ja, die Sache ist wohl so etwas wie ein Zwitter. Also: Ich schreibe eine Anwendung in VB6 (genauer gesagt: ich versuch’ das). Die Daten dazu speichere ich in Datendateien. Das geht am besten, wenn ich diese Daten innerhalb der Anwendung in ein Datenfeld schreibe. Dieses kann ich ja dann in einem Rutsch in eine Datei schreiben, aber das geht wohl nur mit Variant-Datenfeldern.
Es handelt sich dabei um mehrere Datenfelder, wobei die Anwendung in dem einen Datenfeld „nachliest“, aus welchem anderen Datenfeld es erforderliche Daten holen soll. Deswegen könnte man also auch von einer Datenbank sprechen, sozusagen „Carstens Database“:smile:

Da ich nun aber nicht weiß, wieviele Datenfelder es einmal werden (und ich befürchte, es kommen noch einige dazu), mache ich mit Sorgen, ob wohl der Arbeitsspeicher-„Verbrauch“ zu hoch sein könnte. Wahrscheinlich mache ich mir ganz umsonst diese Gedanken!?!?

VG
Carsten

Hallo Reinhard.

? In der Registry. Schreib halt mit Savesetting was
außergewöhnliches rein, „xyz#+zt“ o.ä. und such danch in der
Registry.
Soweit ich weiß bilden zwei Dateien die Registry, User.dat und
system.dat.

Windows reagiert sehr sensibel bzw. knallhart wenn man da
einen Fehler macht.

Wenn die Daten in die Registrierung geschrieben werden, dann muß man die ja spätestens bei einer Deinstallation wieder dort rauskriegen.

Ich weiß ja, daß ich ein „Träumerle“ bin, aber an dieser Stelle muß ich dann sagen, daß ich meine Methode mit den Datendateien besser finde.

Hallo Carsten,

Ja, die Sache ist wohl so etwas wie ein Zwitter. Also:
Ich schreibe eine Anwendung in VB6 (genauer gesagt: ich
versuch’ das). Die Daten dazu speichere ich in Datendateien.

So mit Open … also praktisch in eine Textdatei.

Dieses kann ich ja dann in einem Rutsch in eine Datei schreiben,
aber das geht wohl nur mit Variant-Datenfeldern.

Nein. :smile:

Da ich nun aber nicht weiß, wieviele Datenfelder es einmal
werden (und ich befürchte, es kommen noch einige dazu), mache
ich mit Sorgen, ob wohl der Arbeitsspeicher-„Verbrauch“ zu hoch
sein könnte. Wahrscheinlich mache ich mir ganz umsonst
diese Gedanken!?!?

Das allerdings, die Sorge ist unbegründet. Was Du an ‚Einstellungen‘ für das Programm zwischenspeicherst, stellt den PC vor kein Problem.

Aber deshalb darf man ja das Speichern richtig machen und verstehen. :smile:

Ich rate mal, wie Dein Code aussieht:

Private Type Einstellungen
 Variable1 As String
 ...
End Type

Private Sub schreiben()
 Dim Daten(1 to 10) As Einstellungen
 Open ...
 Put #ff, , Daten
...

Das geht so einfach nicht, das funktioniert nur, wenn die Strings eine feste Länge haben.

Um den Strings eine feste Länge geben zu können, damit sie in einem Rutsch mit Put geschrieben und mit Get gelesen werden können, muss die Deklaration so aussehen:

Private Type Einstellungen
 Variable1 As String \* 20
 Variable2 As Integer
End Type

Mit der festen Länge der Strings geht das dann.

Gruß Rainer

Hallo Rainer.

So mit Open … also praktisch in eine Textdatei.

Jo, mit Open

Private Type Einstellungen
Variable1 As String * 20
Variable2 As Integer
End Type

Ich habe hier 'mal einen Mini-Auszug aus dem Datenfeld, in dem speziell String-Einstellungen für die Anwendung gespeichert werden (hier werden gerade die Werte beim ersten Start der Anwendung festgelegt). Ich habe dafür aber keinen Typen deklariert.

Public MainData() As Variant

...Redim MainData(blablabla)
...Bla
...Bla

MainData(DataCols.CString, MainDataRow.str\_BezeichnungZeit) = "Lohnkosten"
MainData(DataCols.CString, MainDataRow.str\_FontName) = "Tahoma"

Die String-Werte haben alle unterschiedliche Länge, aber ich habe bisher beim Speichern noch nie Probleme deswegen gehabt.Wenn das Datenfeld Variant ist, dann sollte doch die Länge eines String-Wertes egal sein. Ich meine wegen der 16 Bytes, die Du Eingangs erwähnt hast. Ich glaub’, ich bin zu doof dafür.

VG
Carsten

Hallo Carsten,

Public MainData() As Variant
Redim MainData(blablabla)
MainData(DataCols.CString, MainDataRow.str\_BezeichnungZeit) = "Lohnkosten"

Jetzt blicke ich nicht mehr durch.

Du definierst das Array eindimensional und adressierst dann zweidimensional?

Die String-Werte haben alle unterschiedliche Länge, aber
ich habe bisher beim Speichern noch nie Probleme deswegen gehabt.

Grundsätzlich macht das auch kein Problem, wenn Du mit Print jeden Wert einzeln schreibst und mit Input oder Line Input wieder liest.
Nur die bequeme und schnelle Methode mit einem Put/Get ohne Schleife das Array zu schreiben/lesen geht nur mit fester Länge. Dann kann VB eine Zeile in der Datei als ‚Datensatz‘ verstehen und den Inhalt richtig zuordnen, ohne weiteren Code.

Aber ich komme vom Thema ab. :smile:

Zurück zum Platzbedarf:

Du arbeitest ja mit Strings, dann ist es egal, ob Du das Array als String oder Variant deklarierst. Der Speicherverbrauch ist dann gleich.

Aber noch mal etwas weiter in die Tiefe, weil Du scheinbar annimmst, daß Du einen ganzen String in 16 Bytes speichern kannst. Der String kann ja ein MB lang sein, das kann ja unmäglich in 16 Bytes passen, das wäre ja eine wundersame Speichervergrößerung. :smile:

In den 16 Bytes wird natürlich nur ein Zeiger abgelegt, der auf die Adresse im Arbeitsspeicher zeigt, an der die Textdaten des Strings liegen. Die Zeiger liegen im Speicher in direkt aufeinander folgende Bytes, die Daten der Strings nicht! Die packt das BS da hin, wo es gerade Platz findet, der zur Länge des Strings passt. Gespeichert wird die Anfangsadresse des Strings, der String wird dort abgelegt (für jedes Zeichenh werden zwei Bytes benötigt) und hinter den String noch ein ‚NULL‘ Byte als Marke für das Ende geschrieben.

Die 16 Bytes brauchst Du also zusätzlich zu den Daten. Die brauchst Du aber, wenn Du den String als Variant im Speicher hältst und auch, wenn Du die das Array als String deklarierst.

In der Textdatei ist der Platzbedarf dann deutlich geringer, da werden die Daten einfach nur hintereinander geschrieben, jedes Zeichen ein Byte lang, ohne die Liste aus 16 Byte langen Zahlen zur Verwaltung. Die Verwaltung ist ja nicht nötig, wenn die Daten dirrekt hintereinander stehen. Im Arbeitsspeicher tun sie das eben nicht.

Gruß Rainer

Hallo Rainer

Public MainData() As Variant
Redim MainData(blablabla)
MainData(DataCols.CString, MainDataRow.str_BezeichnungZeit) =
„Lohnkosten“

Jetzt blicke ich nicht mehr durch.

Du definierst das Array eindimensional und adressierst dann
zweidimensional?

Nein nein. Ich dimensioniere schon zweidimensional:

ReDim MainData(0 To DataCols.Hex, 0 To MainDataRows)

„DataCols.Hex“ stellt dabei den höchsten Wert einer Enumeration bereit, MainDataRows ist eine Konstante.
Die Enumeration „DataCols“ enhält CBoolean, CInteger, CLong, CSingle, CDouble, CString, CVariant und Hex.
Ich bin sicher, Du erkennst, welche Datentypen in welche „Spalte“ geschrieben werden.

Grundsätzlich macht das auch kein Problem, wenn Du mit Print
jeden Wert einzeln schreibst und mit Input oder Line Input
wieder liest.

Ich schreibe mit Put (und lese mit Get) das komplette Array. Falls die Information noch wichtig ist: Ich schreibe nicht in eine Textdatei, sondern in eine Datendatei mit der Erweiterung „.dat“. Ich habe mal (irrtümlicherweise durch falsche Deklaration des Arrays als String) versucht, dieses Array in eine Datendatei zu „putten“, aber da gab’s dann Mecker. Nach der Deklaration als Variant war das Problem dann weg. Daher auch meine Vermutung, daß man Arrays nur als Variant in eine Datendatei schreiben kann.

Du arbeitest ja mit Strings, dann ist es egal, ob Du das Array

Das Array enthält aber auch alle anderen Datentypen, angeordnet in der jeweiligen „Spalte“, die in der Enumeration „DataCols“ enthalten sind.

Aber noch mal etwas weiter in die Tiefe, weil Du scheinbar
annimmst, daß Du einen ganzen String in 16 Bytes speichern
kannst. Der String kann ja ein MB lang sein, das kann ja
unmäglich in 16 Bytes passen, das wäre ja eine wundersame
Speichervergrößerung. :smile:

In den 16 Bytes wird natürlich nur ein Zeiger abgelegt, der
auf die Adresse im Arbeitsspeicher zeigt, an der die Textdaten
des Strings liegen. Die Zeiger liegen im Speicher in direkt
aufeinander folgende Bytes, die Daten der Strings nicht! Die
packt das BS da hin, wo es gerade Platz findet, der zur Länge
des Strings passt. Gespeichert wird die Anfangsadresse des
Strings, der String wird dort abgelegt (für jedes Zeichenh
werden zwei Bytes benötigt) und hinter den String noch ein
‚NULL‘ Byte als Marke für das Ende geschrieben.

Die 16 Bytes brauchst Du also zusätzlich zu den Daten. Die
brauchst Du aber, wenn Du den String als Variant im Speicher
hältst und auch, wenn Du die das Array als String deklarierst.

In der Textdatei ist der Platzbedarf dann deutlich geringer,
da werden die Daten einfach nur hintereinander geschrieben,
jedes Zeichen ein Byte lang, ohne die Liste aus 16 Byte langen
Zahlen zur Verwaltung. Die Verwaltung ist ja nicht nötig, wenn
die Daten dirrekt hintereinander stehen. Im Arbeitsspeicher
tun sie das eben nicht.

Das muß ich alles noch verdauen, aber danke für die genaue Beschreibung.

VG
Carsten

Hallo Carsten,

„DataCols.Hex“ stellt dabei den höchsten Wert einer Enumeration
bereit, MainDataRows ist eine Konstante.
Die Enumeration „DataCols“ enhält CBoolean, CInteger,
CLong, CSingle, CDouble, CString, CVariant und Hex.
Ich bin sicher, Du erkennst, welche Datentypen in welche
„Spalte“ geschrieben werden.

ahhh, jetzt wird’s klar.

Falls die Information noch wichtig ist: Ich schreibe nicht in
eine Textdatei, sondern in eine Datendatei mit der
Erweiterung „.dat“.

Das ist egal, als Endung darfsr Du schreiben was Du magst.
Du schreibst und liest ja den Inhalt mit Deinem eigenen Programm, dann hat die Endung keine Bedeutung.

Windows erkennt nur Endungen, verwendet dann ein bestimmtes Programm um die Datei zu öffnen, wenn sie doppelt angeklickt wird und erwartet dann, daß das Format dazu passt.

Du klickst die Dateien aber nicht an, deshalb spielt die Endung keine Rolle.

Ich habe mal (irrtümlicherweise durch falsche Deklaration des
Arrays als String) versucht …

Jetzt ist mir klar, daß das Probleme geben muss. Das kann nur funktionieren, wenn die Inhalte alle nur Strings sind.

Aber danke, über das was Du da machst habe ich mir noch nie Gedanken gemacht. Ich hätte aus dem Hut nicht sagen können, od das so möglich istm, hätte ich erst testen müssen.

In ein Variant-Array kann man also unterschiedliche Datentypen gemischt schreiben. Sehr interessant …

OK, klar. Das geht dann natürlich nur mit Variant.

Das funktioniert so wirklich? Ich kann das kaum glauben, muss ich testen. :smile: Wie weit hast Du das getestet? Funktioniert das auch, wenn Felder leer bleiben?

Wie bist Du darauf gekommen? Ich hätte mich das nicht getraut und das anders, wohl viel komplizierter gemacht.

Gruß Rainer

Nachtrag Code Test
Hallo Carsten,

ich habe mir mal einen Test dazu geschrieben, ich bin fast erstaunt, daß das ohne Problem funktioniert. Aber ja, klar, das kann so natürlich nur funktionieren, wenn das Array als Variant deklariert ist.

Gruß Rainer

Dim arr(1 To 5, 1 To 5) As Variant

Private Sub Command1\_Click()
 Dim n As Integer, c As Integer, na As String, ff As Integer
 Dim i As Integer
 Dim l As Long
 Dim s As Single
 Dim d As Double
 Dim st As String

 i = 1
 l = 22
 s = 3.3
 d = 4.4
 st = "Fünf"

 For n = 1 To 5
 If n 2 Then
 arr(n, 1) = n
 arr(n, 2) = l
 'arr(n, 3) = s
 arr(n, 4) = d
 arr(n, 5) = st
 End If
 Next

 na = "C:\Test.dat"
 ff = FreeFile
 Open na For Binary As #ff
 Put #ff, , arr
 Close #ff

 List1.Clear

 For n = 1 To 5
 For c = 1 To 5
 List1.AddItem arr(n, c)
 Next
 Next
End Sub

Private Sub Command2\_Click()
 Dim n As Integer, c As Integer, na As String, ff As Integer
 Dim i As Integer
 Dim l As Long
 Dim s As Single
 Dim d As Double
 Dim st As String

 na = "C:\Test.dat"
 ff = FreeFile
 Open na For Binary As #ff
 Get #ff, , arr
 Close #ff

 List1.Clear

 For n = 1 To 5
 For c = 1 To 5
 List1.AddItem arr(n, c)
 Next
 Next
End Sub

Hallo,

warum legt ihr die Daten nicht in eine DB? Oder Alternativ erstellt eine Klasse als „Datenspeicher“ und erstellt darueber dann eine Collection?
Das ist rel. simple zu lösen, leicht verstaendlich und es spielt dabei keine Rolle wieviele Daten es sind. Auch könnte man dann dort die Daten als Variant declarieren oder halt mehrere Eigenschaften :smile:

MfG Alex