Autor Thema: Out of Stack Space  (Gelesen 4749 mal)

Offline Lloyd

  • Aktives Mitglied
  • ***
  • Beiträge: 211
Out of Stack Space
« am: 04.04.12 - 18:20:50 »
Hi,
ich bekomme in einer meiner Funktionen einen Fehler [Out of Stack Space]. Aus dem Forum habe ich schon rausbekommen dass es sich hierbei scheinbar um eine Rekursion handeln muss. Ich habe jetzt schon alle möglichen Dinge im Script verändert, ich komme aber nicht dahinter wo es klemmt. Kann jemand aus dem Script erkennen wo mein Problem liegen könnte? Ich vermute dass es an der Klasse "ArraySets" liegt, die ich insgesamt 3 mal unter anderem Variablen-Namen verwende (Dim ApplList As New ArraySets, ApplList2 As New ArraySets, ApplList3 As New ArraySets). Sorry für das lange Script, aber ich denke man braucht alle Infos um dem Fehler auf die Spur zu kommen.

Sub Click(Source As Button)
   Dim ws As New NotesUIWorkspace
   Dim uidoc As NotesUIdocument
   Dim s As New NotesSession
   Dim db As NotesDatabase
   Dim importpfad As String
   Dim zeile As String
   Dim tz As String
   Dim cpname As String   
   Dim software As String
   Dim version As String
   Dim installationsdatum As String
   Dim cpnamenum As Integer
   Dim softwarenum As Integer
   Dim versionnum As Integer
   Dim instdatumnum As Integer
   Dim count As Long
   Dim item As NotesItem, item2 As NotesItem
   Dim keys( 1 To 2 ) As String
   Dim connectold As Variant, connectold2 As Variant
   Dim hwentry As Integer, swentry As String
   Dim keywert As String
   Dim item3 As NotesItem
   Dim hwview As NotesView
   Dim hwdoc As NotesDocument
   Dim view As NotesView
   Dim swdoc As NotesDocument
   Dim ndoc As Notesdocument
   
   Set db = s.CurrentDatabase
   Set uidoc = ws.CurrentDocument
   
   Dim ApplList As New ArraySets, ApplList3 As New ArraySets
   Dim ApplList2 As New ArraySets
   Call ApplList3.Init
   
   Set hwview = db.GetView("($cpname)")
   
   importpfad = uidoc.FieldGetText("import_pfad")
   tz = uidoc.FieldGetText("import_tz")
   
   If uidoc.FieldGetText("import_sw_cpname") <> "" Then   
      cpnamenum = uidoc.FieldGetText("import_sw_cpname")
   End If
   If uidoc.FieldGetText("import_sw_name") <> "" Then
      softwarenum = uidoc.FieldGetText("import_sw_name")
   End If
   If uidoc.FieldGetText("import_sw_version") <> "" Then
      versionnum = uidoc.FieldGetText("import_sw_version")      
   End If   
   If uidoc.FieldGetText("import_sw_instdatum") <> "" Then
      instdatumnum = uidoc.FieldGetText("import_sw_instdatum")      
   End If
   
   count = 0   
   Filenum = Freefile
   
   Open importpfad For Input As Filenum
   
   Do While Not Eof( Filenum)
      count = count + 1
      
      Print "Lese Zeile " & Cstr(count) & " Bitte warten ..."
      Line Input #FileNum, zeile
      
      If cpnamenum <> 0 Then
         cpname = Strtoken(zeile, tz, cpnamenum)         
         Set hwdoc = hwview.GetDocumentByKey(cpname)
         If hwdoc Is Nothing Then
            Gosub Weiter    ' Wenn kein Hardwaredokument existiert dann zum nächsten Datensatz in der Importdatei
         End If
      End If
      
      If softwarenum <> 0 Then
         software = Strtoken(zeile, tz, softwarenum)
         keys( 1 ) = software
      End If
      
      If versionnum <> 0 Then
         version = Strtoken ( zeile, tz, versionnum )      
         keys( 2 ) = version
      End If
      
      If instdatumnum <> 0 Then
         installationsdatum = Strtoken ( zeile, tz , instdatumnum )         
      End If      
      
'      Prüfen ob für diese Software ein Massenänderungsdokument existiert und wenn ja dann Namen umbenennen      
%REM      
      swname = Massenänderung_SWName_einzeln(software)   
      
      If (Cstr(swname) <> "") Then
         software = Cstr(swname)
         keys( 1 ) = Cstr(swname)
      End If
%ENDREM      
      
'       ### START Prüfen ob Software Stammdokument schon existiert ###
      Set view = db.GetView("$software")
      
      If (keys(2) <> "") And (keys(2) <> " ") Then
         Set swdoc = view.GetDocumentByKey(keys)
      Else         
         Set swdoc = view.GetDocumentByKey(software)         
      End If
      
      If Not swdoc Is Nothing Then   '(1)
BestehendeSofware:
'         Print "Lizenzblatt existiert"
         ' Wenn Lizenzblatt existiert dann nur verknüpfen mit Hardware
         Call ApplList.Init         
         connectold = swdoc.GetItemValue("sw_connections")         
         
         If (connectold(0) = "") Then
            ApplList.AddElement ( hwdoc.UniversalID)
         Else
            Forall c In connectold
               ApplList.AddElement ( c)            
            End Forall
         End If         
         
         hwentry = ApplList.Search(Cstr(hwdoc.UniversalID))
         
         If (hwentry <> 0) Then
            ' Wenn der CPName schon existiert dann nicht verknüpfen
'            Print "Der PCName wurde im Softwareblatt bereits verknüpft"
            Call ApplList2.Init
            connectold2 = hwdoc.GetItemValue("sw_connections")         
            If (connectold2(0) = "") Then
               ApplList2.AddElement ( swdoc.UniversalID)
            Else
               Forall d In connectold2
                  ApplList2.AddElement ( d)               
               End Forall
            End If   
            swentry = ApplList2.Search(Cstr(hwdoc.UniversalID))
            If (swentry = 0) Then
'      Print "Die Software wurde noch nicht im Hardwaredokument verknüpft"
               Set item3 = hwdoc.GetFirstItem( "sw_connections" )
               Call item3.AppendToTextList( swdoc.UniversalID)
               Call hwdoc.Save(True,False)            
            Else
'      Print "Die Software wurde bereits im Hardwaredokument verknüpft"
            End If   
         Else
            ' Wenn der CPNAME nicht existiert dann verknüpfen
'            Print "Der PCName wurde im Softwareblatt noch nicht verknüpft"
            
            ' Verknüpfe PC im Softwaredokument
            Set item = swdoc.GetFirstItem( "sw_connections" )
            Call item.AppendToTextList( hwdoc.UniversalID)
            Call swdoc.Save(True,False)
            Call ApplList2.Init
            connectold2 = hwdoc.GetItemValue("sw_connections")         
            If (connectold2(0) = "") Then
               ApplList2.AddElement ( swdoc.UniversalID)
            Else
               Forall d In connectold2
                  ApplList2.AddElement ( d)               
               End Forall
            End If   
            swentry = ApplList2.Search(Cstr(hwdoc.UniversalID))
            If (swentry = 0) Then
'      Print "Die Software wurde noch nicht im Hardwaredokument verknüpft"
               Set item3 = hwdoc.GetFirstItem( "sw_connections" )
               Call item3.AppendToTextList( swdoc.UniversalID)
               Call hwdoc.Save(True,False)            
            Else
'      Print "Die Software wurde bereits im Hardwaredokument verknüpft"
            End If   
         End If         
      Else   '(1)
         ' Wenn Lizenzblatt nicht existiert dann erst neues Lizenzblatt anlegen und dann mit Hardware verknüpfen
         swentry = ApplList3.Search_Extended(software)         
         If (swentry = "") Then   '(2)
NeueSoftware:
'            Print "Es existiert noch kein Lizenzblatt zu dieser Software"
            Set ndoc = db.CreateDocument
            ndoc.Form = "lizenzblatt"
            ndoc.lizenz_swname = software
            ndoc.lizenz_swversion = version
            ndoc.lizenz_typ = "Unbestimmt"
            ndoc.sw_connections = hwdoc.UniversalID   ' Verknüpfe PC im Softwaredokument
            
            Call ndoc.ComputeWithForm(True,False)
            Call ndoc.Save(True,False)
            
            ApplList3.AddElement ( software & "##" & ndoc.UniversalID )
            
            Call ApplList2.Init
            connectold2 = hwdoc.GetItemValue("sw_connections")         
            If (connectold2(0) = "") Then
               ApplList2.AddElement ( ndoc.UniversalID)
            Else
               Forall d In connectold2
                  ApplList2.AddElement ( d)               
               End Forall
            End If   
            swentry = ApplList2.Search(Cstr(hwdoc.UniversalID))
            If (swentry = 0) Then
'      Print "Die Software wurde noch nicht im Hardwaredokument verknüpft"
               Set item3 = hwdoc.GetFirstItem( "sw_connections" )
               Call item3.AppendToTextList( ndoc.UniversalID)
               Call hwdoc.Save(True,False)            
            Else
'      Print "Die Software wurde bereits im Hardwaredokument verknüpft"
            End If   
         Else      '(2)
            Set swdoc = db.GetDocumentByUNID(swentry)
            If Not swdoc Is Nothing Then
               Gosub BestehendeSofware
            Else
               Gosub NeueSoftware
            End If
         End If   '(2)
      End If   '(1)
'       ### ENDE Prüfen ob Software Stammdokument schon existiert ###      
Weiter:
   Loop   
   Close #FileNum
End Sub

'==========================================================================================
' START C L A S S "ArraySets"
'==========================================================================================
Class ArraySets
   Public Value() As String
   Public TotalElements As Long
   
   Sub Init
      TotalElements = 0
      Redim Value(1 To 1) As String
   End Sub
   
   Sub AddElement(NewValue As String)
      TotalElements = TotalElements + 1
      Redim Preserve Value(1 To TotalElements) As String
      Value(TotalElements) = NewValue
   End Sub
   
   Function Search(SearchFor As String) As Integer
      Dim CurrentLabelEntry As Integer
      CurrentLabelEntry = 0
      Forall c In Value
         If Ucase(c) = Ucase(SearchFor) Then
            CurrentLabelEntry = CurrentLabelEntry + 1
         End If
      End Forall
      Search = CurrentLabelEntry
   End Function
   
   Function Search_Extended(SearchForString As String) As String
      Dim CurrentLabelEntry As String
      CurrentLabelEntry = ""
      Forall c In Value
         If Strleft(Ucase(c),"##") = Ucase(SearchForString) Then
            CurrentLabelEntry = Strright(c,"##")
         End If
      End Forall
      Search_Extended = CurrentLabelEntry
   End Function
   
End Class
'==========================================================================================
' ENDE C L A S S "ArraySets"
'==========================================================================================
Gruss
Lloyd

Offline koehlerbv

  • Moderator
  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 20.460
  • Geschlecht: Männlich
Re: Out of Stack Space
« Antwort #1 am: 04.04.12 - 20:26:17 »
Wo ist Dein ErrorHandling, das Dir sagt, in welcher Zeile es knallt?
Ohne dieses Minimum guten Codings bist Du hilflos - und wir eher nicht gewillt, unter diesen Umständen Deinen Code "blind" durchzuflöhen.

Bernhard

Offline Lloyd

  • Aktives Mitglied
  • ***
  • Beiträge: 211
Re: Out of Stack Space
« Antwort #2 am: 05.04.12 - 09:48:35 »
Hallo Bernhard,
du hast natürlich recht. Ich hatte den Code auf das Minimum zusammengeschrumpft, bevor ich den hier eingestellt habe. Anbei der Screenshot meiner Fehlerbehandlung, die vorher mal drin war:

Der Fehler tritt dabei in Zeile 177 auf, was die folgende CodeZeile ist:

   swentry = ApplList3.Search_Extended(software)   

Gruss
Lloyd

Offline Pyewacket

  • Senior Mitglied
  • ****
  • Beiträge: 310
  • Geschlecht: Männlich
Re: Out of Stack Space
« Antwort #3 am: 05.04.12 - 10:29:49 »
Die Fehlermeldung [Out of Stack Space] sagt eigentlich ziemlich genau was passiert.

      
      If cpnamenum <> 0 Then
         cpname = Strtoken(zeile, tz, cpnamenum)         
         Set hwdoc = hwview.GetDocumentByKey(cpname)
         If hwdoc Is Nothing Then
==>            Gosub Weiter    ' Wenn kein Hardwaredokument existiert dann zum nächsten Datensatz in der Importdatei
         End If
      End If
   .........   
Weiter:
   Loop   
   Close #FileNum
End Sub
Du willst hier ans Ende der Schleife springen aber anstatt GOTO verwendest du GOSUB mit dem das Unterprogramm "Weiter" aufgerufen wird.

Bei jedem GOSUB merkt sich Lotusscript auf dem Stack die Adresse nach dem GOSUB um beim Ende des Unterprogrammes bei Ausführung der RETURN Anweisung zu wissen wohin es zurückspringen muss.  Nun gibt es bei dir aber kein RETURN und so wird die Liste der Rücksprungadressen auf dem Stack immer größer bis es dann mal knallt weil kein Speicher mehr frei ist.
Soweit ich weiss ist die Stackgrösse auf 32K limtiert, versuchweise reicht das etwa für 2000 Aufrufe oder weniger, je nachdem was sonst noch auf dem Stack ist.

Ersetze alle GOSUB durch ein GOTO und dieser Fehler dürfte dann nicht mehr auftreten.
Noch besser wäre wenn du die Programmlogik änderst und erst gar kein GOTO verwendest,
momentan ist das ziemlich unübersichtlich und in einem halben Jahr blickst du selber nicht mehr durch.

Gruss
 Peter
ATOS.org - Feel the music!

Offline Lloyd

  • Aktives Mitglied
  • ***
  • Beiträge: 211
Re: Out of Stack Space
« Antwort #4 am: 05.04.12 - 11:16:16 »
Hallo Peter,
du hast ja sowas von Recht. VIELEN VIELEN DANK. Da wäre ich nie drauf gekommen!

Und ja du hast nochmal recht: Das sieht sehr unübersichtlich aus. Das liegt aber daran dass ich sämtliche Funktionen zusammengefasst habe, damit es im Forum etwas "übersichtlicher/nachvollziehbarer" wird. Nachdem du mir jetzt den Fehler aufgezeigt hast, baue ich das wieder um.

Nochmal herzlichen Dank, vor allem für die ausführliche Erläutern der Fehlerursache. Damit habe ich auch verstanden warum das passiert.

Ach ja, du hast auch ein Drittes mal recht. Der Fehler trat in der Tat nach etwas mehr als dem 2000 Aufruf auf.
Gruss
Lloyd

Offline flaite

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 2.966
    • mein del.icio.us
Turn on, tune in, drop out
« Antwort #5 am: 05.04.12 - 15:47:20 »
http://www.cleancoders.com/

Du hast die hier wohl angebrachten ca 10 privaten Funktionen per Hand ge-inlined, um das zu posten  ??? Mir ist das völlig egal, aber da reservier ich mir ein paar hmm Zweifel. Aber wie gesagt, total egal. Kauft ein paar Folgen von obigen Film.
Ich stimm nicht mit allen überein, aber mit vielen und sowieso unterhaltsam -> https://www.youtube.com/channel/UCr9qCdqXLm2SU0BIs6d_68Q

---

Aquí no se respeta ni la ley de la selva.
(Hier respektiert man nicht einmal das Gesetz des Dschungels)

Nicanor Parra, San Fabian, Región del Bio Bio, República de Chile

 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz