Arbeitsspeicherbedarf VB-Programm

HuBaer

Ensign
Registriert
Aug. 2006
Beiträge
177
Hallo allerseits,

ich habe mit Visual Basic ein kleines Programm geschrieben. Leider reserviert dieses bei der Ausführung von Haus aus über vier MB Arbeitsspeicher, obwohl in dem Programm nur ganz einfache Befehle, wie z.B. Programm ausführen, Datei erstellen etc. vorkommen. Vier MB sind zwar für heutige Verhältnisse nicht viel, allerdings wird das Programm bis zu zehn mal gleichzeitig ausgeführt und dann kann es bei einem älteren Rechner schon mal knapp werden!

Ist das normal oder lässt sich da was machen?

Gruß
 
Option Explicit

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long

Const SW_MINIMIZE = 6

'Diverse APIs deklarieren
Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" ( _
ByVal lpAppName As Long, _
ByVal lpCmdLine As String, _
ByVal lpProcAttr As Long, _
ByVal lpThreadAttr As Long, _
ByVal lpInheritedHandle As Long, _
ByVal lpCreationFlags As Long, _
ByVal lpEnv As Long, _
ByVal lpCurDir As Long, _
lpStartupInfo As STARTUPINFO, _
lpProcessInfo As PROCESS_INFORMATION _
) As Long

Private Declare Function WaitForSingleObject Lib "kernel32" ( _
ByVal hHandle As Long, _
ByVal dwMilliseconds As Long _
) As Long

Private Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long _
) As Long

'Einige Konstanten benennen
Private Const NORMAL_PRIORITY_CLASS As Long = &H20&
Private Const INFINITE As Long = -1&
Private Const WAIT_TIMEOUT As Long = 258&

'Einige Datentypen erstellen
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Integer
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type

Private Sub Form_Load()

Dim iKanalNr

Dim Zeit
Dim Datum
Dim Alarmzeit
Dim Alarmdatum

Datum = Date

Zeit = Time
Zeit = Left(Zeit, 5)

Dim ZeitarrayLang
Dim Sekunden
ZeitarrayLang = Array()
ZeitarrayLang = Split(Time, ":")
Sekunden = ZeitarrayLang(2)

Dim AlleParameter
Dim Parameter1
Dim Parameter2
AlleParameter = Array()
AlleParameter = Split(Command)
Parameter1 = AlleParameter(0)
Parameter2 = AlleParameter(1)

If Sekunden = 58 Then
Sleep (3000)
GoTo weiter
End If
If Sekunden = 59 Then
Sleep (3000)
GoTo weiter
End If
If Sekunden = 0 Then
Sleep (3000)
GoTo weiter
End If
If Sekunden = 1 Then
Sleep (3000)
GoTo weiter
End If
If Sekunden = 2 Then
Sleep (3000)
GoTo weiter
End If

weiter:

If CheckPath("D:\Alarmierung\Reloadsperren\Alarmzeit.txt") = False Then
iKanalNr = FreeFile()
Open "D:\Alarmierung\Reloadsperren\Alarmzeit.txt" For Append As iKanalNr
Print #iKanalNr, Zeit
Close iKanalNr
End If

If CheckPath("D:\Alarmierung\Reloadsperren\Alarmdatum.txt") = False Then
iKanalNr = FreeFile()
Open "D:\Alarmierung\Reloadsperren\Alarmdatum.txt" For Append As iKanalNr
Print #iKanalNr, Datum
Close iKanalNr
End If

If Parameter1 = "ALARM" Then GoTo start
GoTo beenden
start:
If CheckPath("D:\Alarmierung\Reloadsperren\" & Parameter2 & ".tmp") = True Then GoTo ende_reloaded

iKanalNr = FreeFile()
Open "D:\Alarmierung\Reloadsperren\" & Parameter2 & ".tmp" For Append As iKanalNr
Print #iKanalNr, ""
Close iKanalNr

Dim Probealarmwert

ShellWait "D:\Alarmierung\Probealarmzeiten.bat " & Parameter2, True
If CheckPath("D:\Alarmierung\Reloadsperren\" & Parameter2 & "_Probe.tmp") = True Then GoTo Probe

If Parameter2 = "Traunstein3-2" Then
Kill ("D:\Alarmierung\Reloadsperren\" & Parameter2 & ".tmp")
GoTo beenden
End If

ShellExecute hwnd, "open", "D:\Alarmierung\Benutzerliste.bat", Parameter2 & " Immer", "D:\Alarmierung", SW_MINIMIZE

Do
Sleep (500)
Loop Until CheckPath("D:\Alarmierung\Reloadsperren\Count120.tmp") = False

If CheckPath("D:\Alarmierung\Reloadsperren\1.tmp") = True Then GoTo start2
iKanalNr = FreeFile()
Open "D:\Alarmierung\Reloadsperren\1.tmp" For Append As iKanalNr
Print #iKanalNr, ""
Close iKanalNr

If CheckPath("D:\Alarmierung\Reloadsperren\Count120_run.tmp") = False Then
ShellExecute hwnd, "open", "D:\Alarmierung\Tools\Count120.bat", 0, "D:\Alarmierung", SW_MINIMIZE
iKanalNr = FreeFile()
Open "D:\Alarmierung\Reloadsperren\Count120_run.tmp" For Append As iKanalNr
Print #iKanalNr, ""
Close iKanalNr
End If

iKanalNr = FreeFile()
Open "D:\Alarmierung\Reloadsperren\Alarmdatum.txt" For Input As iKanalNr
Line Input #iKanalNr, Alarmdatum
Close iKanalNr

If CheckPath("D:\Alarmierung\SMS\Weitere.txt") = False Then
iKanalNr = FreeFile()
Open "D:\Alarmierung\SMS\Weitere.txt" For Append As iKanalNr
Print #iKanalNr, "!!!Alarm!!! " & Alarmdatum & " Alarmiert: FW " & Parameter2 & ", "
Close iKanalNr
End If

ShellExecute hwnd, "open", "D:\Alarmierung\Benutzerliste.bat", Parameter2 & " X", "D:\Alarmierung", SW_MINIMIZE

Do
Sleep (500)
Loop Until CheckPath("D:\Alarmierung\Reloadsperren\Count120.tmp") = True
GoTo Weitere

start2:

iKanalNr = FreeFile()
Open "D:\Alarmierung\SMS\Weitere.txt" For Append As iKanalNr
Print #iKanalNr, "FW " & Parameter2 & ", "
Close iKanalNr

If CheckPath("D:\Alarmierung\Reloadsperren\2.tmp") = False Then
iKanalNr = FreeFile()
Open "D:\Alarmierung\Reloadsperren\2.tmp" For Append As iKanalNr
Print #iKanalNr, ""
Close iKanalNr
End If

Do
Sleep (500)
Loop Until CheckPath("D:\Alarmierung\Reloadsperren\Count120.tmp") = True
GoTo Weitere_Immer

Weitere:

If CheckPath("D:\Alarmierung\Reloadsperren\2.tmp") = False Then GoTo beenden

If CheckPath("D:\Alarmierung\SMS\Weitere_temp.txt") = False Then
FileCopy "D:\Alarmierung\SMS\Weitere.txt", "D:\Alarmierung\SMS\Weitere_temp.txt"
End If

ShellExecute hwnd, "open", "D:\Alarmierung\Benutzerliste.bat", Parameter2 & " Weitere", "D:\Alarmierung", SW_MINIMIZE

Sleep (1000)

GoTo beenden

Weitere_Immer:

If CheckPath("D:\Alarmierung\Reloadsperren\2.tmp") = False Then GoTo beenden

If CheckPath("D:\Alarmierung\SMS\Weitere_temp.txt") = False Then
FileCopy "D:\Alarmierung\SMS\Weitere.txt", "D:\Alarmierung\SMS\Weitere_temp.txt"
End If

ShellExecute hwnd, "open", "D:\Alarmierung\Benutzerliste.bat", Parameter2 & " Weitere_Immer", "D:\Alarmierung", SW_MINIMIZE

Sleep (1000)

GoTo beenden

Probe:

Kill "D:\Alarmierung\Reloadsperren\" & Parameter2 & "_Probe.tmp"

ShellExecute hwnd, "open", "D:\Alarmierung\Benutzerliste.bat", Parameter2 & " Probe", "D:\Alarmierung", SW_MINIMIZE

beenden:

If CheckPath("D:\Alarmierung\Reloadsperren\1.tmp") = True Then Kill "D:\Alarmierung\Reloadsperren\1.tmp"
If CheckPath("D:\Alarmierung\Reloadsperren\2.tmp") = True Then Kill "D:\Alarmierung\Reloadsperren\2.tmp"
If CheckPath("D:\Alarmierung\Reloadsperren\" & Parameter2 & ".tmp") = True Then Kill "D:\Alarmierung\Reloadsperren\" & Parameter2 & ".tmp"
If CheckPath("D:\Alarmierung\Reloadsperren\Count120.tmp") = True Then Kill "D:\Alarmierung\Reloadsperren\Count120.tmp"
If CheckPath("D:\Alarmierung\SMS\Weitere.txt") = True Then Kill "D:\Alarmierung\SMS\Weitere.txt"
If CheckPath("D:\Alarmierung\Reloadsperren\Alarmzeit.txt") = True Then Kill "D:\Alarmierung\Reloadsperren\Alarmzeit.txt"
If CheckPath("D:\Alarmierung\Reloadsperren\Alarmdatum.txt") = True Then Kill "D:\Alarmierung\Reloadsperren\Alarmdatum.txt"


Sleep (10000)

If CheckPath("D:\Alarmierung\SMS\Weitere_temp.txt") = True Then Kill "D:\Alarmierung\SMS\Weitere_temp.txt"

ende_reloaded:

End Sub

Function CheckPath(ByVal sPath As String) As Boolean
If Dir$(sPath, vbDirectory) = "" Then
CheckPath = False
Else
CheckPath = True
End If
Exit Function
End Function

Public Function ShellWait(cmdline As String, Optional ByVal bShowApp As Boolean = False) As Boolean

'Diese Funktion führt einen Befehl (in CmdLine) aus.
'Dabei wird das sich öffnende Fenster unsichtbar gemacht.
'Diese Funktion wird erst beendet, wenn der Befehl
'vollständig abgearbeitet ist.

'Speicher reservieren
Dim uProc As PROCESS_INFORMATION
Dim uStart As STARTUPINFO
Dim lRetVal As Long

'Die Datentypen initialisieren
uStart.cb = Len(uStart)
uStart.wShowWindow = Abs(bShowApp)
uStart.dwFlags = 1

'Statusmeldung
'Label1.Caption = "Starte Notepad"
'Label1.Refresh

'Fenster erzeugen
lRetVal = CreateProcess(0&, cmdline, 0&, 0&, 1&, _
NORMAL_PRIORITY_CLASS, 0&, 0&, uStart, uProc)

If lRetVal = 0 Then
Call MsgBox("Starten der Anwendung ist fehlgeschlagen!", _
vbExclamation + vbOKOnly, App.Title)

ShellWait = False
Exit Function
End If

'Statusmeldung
'Label1.Caption = "Warte auf das Ende der Anwendung"
'Label1.Refresh

'Warten, bis Fenster beendet wurde
'Dabei das eigene Fenster aktualisieren
Do While WaitForSingleObject(uProc.hProcess, 10) = WAIT_TIMEOUT
DoEvents
Loop

'Wenn man solange warten will, bis die Anwendung beendet
'wird und nicht darauf achtet, dass die wartende Anwendung
'dabei absolut zum Stillstand kommt.
lRetVal = WaitForSingleObject(uProc.hProcess, INFINITE)

'Statusmeldung
'Label1.Caption = "Anwendung beendet"
'Label1.Refresh

'Fenster schließen
lRetVal = CloseHandle(uProc.hProcess)

'Rückgabewert setzen
ShellWait = (lRetVal <> 0)
End Function
 
Zu Deinem Problem kann ich erstmal nichts konkretes sagen. Ich würde mal vermuten das die Runtime von VB auch schon einiges an Speicher braucht. Teste doch mal ein leeres Programm wieviel Speicher das benötigt.

Warum ich aber poste, sind folgende Verbesserungsvorschläge:

- Der Befehl GOTO hat in einem Programm nichts verloren, er macht den Code unübersichtlich, damit fehleranfälliger und extrem schwierig zu warten. Ändere an dem Code mal etwas in einem halben Jahr.

- Variablen sollten am Anfang einmal deklariert werden. Mitten im Code senkt das die Übersichtlichkeit deutlich.

- Du verwendest sehr häufig sleep Befehle. Unter anderem heisst das, das man das Programm nicht einfach jederzeit beenden kann, da es auf ein Programmende z.B. aus dem Datei Menü nicht reagieren kann. Ausserdem ist das auch sehr schlecht zu debuggen, da man ja immer wieder warten muss bis der sleep Befehl zu Ende ist oder man muss dauernd per Debugger eingreifen. Hier wäre eine andere Ablauflogik sehr hilfreich.
Gleichzeitig könnte man dabei auch die GOTO Befehle entfernen.

Z.B. das hier lässt sich sicher auch eleganter formulieren:
Code:
If Sekunden = 58 Then
Sleep (3000)
GoTo weiter
End If
If Sekunden = 59 Then
Sleep (3000)
GoTo weiter
End If
If Sekunden = 0 Then
Sleep (3000)
GoTo weiter
End If
If Sekunden = 1 Then
Sleep (3000)
GoTo weiter
End If
If Sekunden = 2 Then
Sleep (3000)
GoTo weiter
End If

weiter:

z.B.:

Code:
If (Sekunden >= 58 AND sekunden <=59) OR (sekunden >=0 AND sekunden <=2)  Then
    Sleep (3000)
End If

Du scheinst oft darauf zu warten ob eine Datei vorhanden ist. Meines Wissens nach gibt es auch die Möglichkeit sich vom Explorer benachrichtigen zu lassen ob sich im Dateisystem etwas geändert hat. Gemacht habe ich das allerdings noch nicht.

MfG

Arnd
 
Zuletzt bearbeitet:
@Arnd: Danke für deine Tipps. Ich werde mal schauen, was sich machen lässt!


Grüße
 
Entstanden ist dieses VB-Programm aus folgendem Grund: Ich hatte vorher alles mit Batch gemacht, brauchte aber dann unbedingt eine Do-schleife und darum habe ich mir für die Batch-Befehle entsprechenden VB-Befehle herausgesucht und alles einfach 1:1 umgeschreiben.
Dass ich bei einem Sleep-Befehl nicht in das programm eingreifen kann, macht nichts. Wie schon im alten Batch-Programm musste ich ja nie interagieren, sondern alles lief von selber ab. Das Fenster ist von daher eigentlich eher störend. Kann man das zufällig irgendwie unsichtbar machen oder zumindest bei Beendigung des Programms automatisch schließen lassen?
Dass goto-Befehle ein Programm unübersichtlich machen, glaub ich gerne. Allerdings habe ich keien ahnung, wie ich diese ersetzen könnte. Außerdem ist der Code ja noch nicht so groß, von daher gehts eigentlich noch mit der Übersichtlichkeit.


Gruß
 
Ich habe den quellcode nicht durchgelesen. Soviel vorab ^^

Ich hatte ein ähnliches Problem, daß mein Programm nach mehreren Minuten auf viel Speicher zurückgriff. Das Problem war bei mir, daß nicht mehr benötigte Konstanten (bei mir waren es sogar ganze Objekte vom Typ Image) nicht aus dem Speicher selbst entfernt wurden, sondern erst nach einer "Ruhe Phase". Ein
Code:
GC.Collet()
half mir allerdings dieses Problem zu bezwinken. Der Garabage Collector wird mit diesem Befehl gezwungen, nullierbare Variablen (a= null; ) Objekte zu entfernen.

Bei mir war das alles in c#, aber VB muss das ja auch haben, beides gehört zu .NET 2.0

Gruß
 
Slightly OT:

Den Spruch "GOTO hat in einer Programmiersprache nichts verloren" hört man immer wieder. Doch ich bitte zu bedenken, dass man in diesem Zitat vor das Wort "Programmiersprache" noch das Adjektiv "höhere" hinzufügen sollte, da der Computer in der internen Abarbeitung auch Befehle überspringt (nichts anderes macht ein IF...THEN...ELSE). In Assembler kommt man beispielsweise ohne LABELs und GOTOs kaum aus.

Höhere Programmiersprache (BASIC, C/C++, Pascal usw.):

IF (Bedingung)
{
Anweisung1
Anweisung2
}
else
{
Anweisung 3
Anweisung 4
}

wird kompiliert zu:

PRÜFE Bedingung
WENN FALSCH, SPRINGE ZU "else" (conditional Jump)
Anweisung1
Anweisung2
SPRINGE ZU "ende" (unconditional Jump)
else:
Anweisung3
Anweisung4
ende:




Ich bitte soetwas auch immer wieder mit in die belehrenden Zitate über GOTO mit einzubeziehen!

Moral: Kein GOTO in höheren Programmiersprachen!
 
Zuletzt bearbeitet: (Grammatik)
On Topic:

Folgende Betrachtungen (Grundstrukturen):

*ein 32Bit-Integer benötigt (wer hätte es anders erwartet?) 32 Bit (also 4 Byte) im Speicher
*ein C-String (also Null-terminiert) benötigt <Anzahl an Buchstaben im String> + 1 Byte (Nullzeichen = Terminator) im Speicher
*ein VB-String könnte folgendes beinhalten (Länge als 32Bit-Wert + Referenzzähler [32 Bit] à la Object Pascal) - demnach 2x 32 Bit als "Header" + Nutzdaten (Buchstaben)

*Simple Arrays benutzen demnach <Anzahl Arrayelemente> * <Speicherbedarf eines Elements> Speicher

Wieviel Speicher ein Objekt (beispielsweise ein Bild) benötigt, hängt von den intern genutzten Grundstrukturen und den Nutzdaten ab.

--------------------------

Gerade Compiler, die ihre eigenen Fensterklassen mitbringen (C++ Builder, Visual Basic, Delphi) überladen ihre Fenster gerne mit Informationen, die der Programmierer im Endeffekt gar nicht mehr benötigt. Trotzdem sind sie Ballast, die das Programm in der Programmdatei und erst recht im Speicher aufblähen.
D.h.: gerade Fenster bringen in einer Anwendung sehr viel Speicherbedarf mit.
 
Hallo XunnD,

als einzige Ausnahme würde ich Assembler (oder andere Varianten davon) gelten lassen. Da wird es eventuell etwas schwierig ohne GOTOs. Aber auch in Assembler kann man einen guten und einen schlechten Programmierstil pflegen.

D.h. kreuz und quer springen in der Programmstruktur nur weil es geht, ist nicht schön. Das hat mit der Programmiersprache eher wenig zu tun.

Auf der Ebene der Maschinensprachen ist diese allgemeine Aussage "GOTO nicht verwenden", dann so sicher nicht mehr gültig. Ich würde dann sagen "GOTO sinnvoll und minimal anwenden".

@HuBaer,

bzgl Fenster unsichtbar machen. Schau Dir mal die Funktion ShowWindow aus dem Win32 API an. Es sollte aber auch eine Eigenschaft der Form geben um sie unsichtbar zu machen.

MfG

Arnd
 
Zuletzt bearbeitet:
Naja, genau das meinte ich ja, Arnd - Den Grundsatz "GOTO nicht verwenden" nur auf höhere Programmiersprachen verwenden.
 
Zurück
Oben