title: Call Stack size?
body: <p>Greetings from Michigan,</p>
  
  <p>I have a program that runs continuously (logging data) where it runs inside a While loop within one Sub ("logging data" Sub), then when the log file becomes "full", it jumps to another Sub to create a new file, then jumps back to the "logging data" Sub to continue on.  Anyway, it keeps doing this and can run for hours like this, creating 100+ files or more of data.  The problem is that the program crashes at some point and it always crashes within this part of the program (one of these two subs, although I haven't pinpointed which one.  When I run the debugger on the machine in which the program is deployed, the Call Stack is rather large.  I'm wondering if that is a problem, and how is that managed.  Could that be the reason for the program crashing (Call stack getting too large?).  I have gotten some sort of memory exception error on at least one of the crashes.  I made some edits to the code yesterday to try and alleviate this.  This last crash (this morning when I got into the office) that I experienced was a nullreference exception error, although I can't pinpoint where unless I run the program from my development machine in debug mode, which I plan to do next to catch exactly what line of code the crash is happening within either of these two Subs.  I'll need to run it overnight as like I said, the program can run for hours before a crash occurs.  Anyway, the question is in regards to the Call Stack.  Is the large Call Stack a problem?  How is that managed/cleared?  </p>
  
  <p>Thanks,
  D</p>
  
  <pre><code>Public Sub dataAcquiring()
      'Receive the collection of channels in this sub and append data to each of the channels
      'Set up the channel group
      Dim message1 As String = "The data file may have been deleted or moved prior to a new data file and directory being created.  Check the main 'Data' directory and be sure the file exists, or simply create a new data file."
      Dim testBool As Boolean = False
  
      'Set the global variable to True if running the application from the development machine in debug mode.  Otherwise, initialize it to false for deployment.
      If Connectlocal = True Then
          statsFile = "C:\Users\dmckin01\Desktop\Data\" &amp; folderName &amp; "\" &amp; dataFileName &amp; "_stats.csv"
      Else : statsFile = "D:\Data\" &amp; folderName &amp; "\" &amp; dataFileName &amp; "_stats.csv"
      End If
  
      Try
          logFile.Open()
      Catch ex As Exception
          MessageBox.Show(Me, ex.Message &amp; message1, "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error)
          cbRecord.Checked = False
          Return
      End Try
  
      Dim i As Integer = 0, n As Integer = 0, hvar As Integer, value As Single, count As Integer = 0, maxValue As Single
      Dim b As Boolean = False, returnValue As Type, stringVar As String, lastValidNumber As Integer
      Dim dtype As System.Type
      Dim channelGroupName As String = "Main Group"
      Dim channelGroup As TdmsChannelGroup = New TdmsChannelGroup(channelGroupName)
      Dim channelGroups As TdmsChannelGroupCollection = logFile.GetChannelGroups()
  
      If (channelGroups.Contains(channelGroupName)) Then
          channelGroup = channelGroups(channelGroupName)
      Else
          channelGroups.Add(channelGroup)
      End If
  
      'Set up the TDMS channels
      Dim Names As String() = New String(13) {" Spindle Speed (rpm) ", " Oil Flow (ccm) ", " Torque (Nm) ", " LVDT Displacement (mm) ", " Linear Pot Displacement (mm) ", _
                                                       " Pneu. Actuator (0=OFF, 1=ON) ", " Elec. Actuator (0=OFF, 1=ON) ", " Hydr. Actuator (0=OFF, 1=ON) ", _
                                                       " Upper Tank Oil Temp. (°F) ", " Lower Tank Oil Temp. (°F) ", " Exit Oil Temp. (°F) ", _
                                                       " Inlet Oil Temp. (°F) ", " Part Temp. (°F) ", " Time Stamp "}
      Dim dataArrayNames As String() = New String(13) {"arrSpeed", "arrFlow", "arrTorque", "arrLVDT", "arrLinPot", "arrActPneu", "arrActElec", "arrActHydr", _
                                                       "arrUpperOil", "arrLowerOil", "arrExitOil", "arrInletOil", "arrTestPart", "arrTimeStamp"}
  
      Dim OPCTagNames As String() = New String(13) {"peakTorque", "peakTorqueSpeed", "peakTorquePlatePos", "timeToPeakTorque", "firstPeakTorque", "firstPeakTorqueSpeed", _
                                                  "firstPeakTorquePlatePos", "timeToFirstPeakTorque", "peakDecel", "peakJerk", "engagementSpeed", "slidePlateSpeed", _
                                                  "timeOfEngagement", "totalEnergy"}
  
  
      Dim bools As Boolean() = New Boolean(13) {recSpeed, recOilFlow, recTorque, recLVDT, recLinPot, recActPneu, recActElec, recActHydr, recUpperOil, recLowerOil, _
                                                recExitOil, recInletOil, recTestPart, recTimeStamp}
  
      'Instantiate the TDMS channels to be used.  We have to do this each and every time this Sub is executed because National Instruments
      'does not have a method to 'clear' the channel group.
      Dim ch0 As TdmsChannel = New TdmsChannel(Names(0), TdmsDataType.Float)   'spindle speed
      Dim ch1 As TdmsChannel = New TdmsChannel(Names(1), TdmsDataType.Float)   'oil flow
      Dim ch2 As TdmsChannel = New TdmsChannel(Names(2), TdmsDataType.Float)   'torque
      Dim ch3 As TdmsChannel = New TdmsChannel(Names(3), TdmsDataType.Float)   'actuator position (LVDT)
      Dim ch4 As TdmsChannel = New TdmsChannel(Names(4), TdmsDataType.Float)   'actuator position (LINEAR POT)
      Dim ch5 As TdmsChannel = New TdmsChannel(Names(5), TdmsDataType.Float) 'actuator state (pneu)
      Dim ch6 As TdmsChannel = New TdmsChannel(Names(6), TdmsDataType.Float) 'actuator state (elec)
      Dim ch7 As TdmsChannel = New TdmsChannel(Names(7), TdmsDataType.Float) 'actuator state (hydr)
      Dim ch8 As TdmsChannel = New TdmsChannel(Names(8), TdmsDataType.Float)  'upper oil tank temp
      Dim ch9 As TdmsChannel = New TdmsChannel(Names(9), TdmsDataType.Float)  'lower oil tank temp
      Dim ch10 As TdmsChannel = New TdmsChannel(Names(10), TdmsDataType.Float) 'Exit oil tank temp
      Dim ch11 As TdmsChannel = New TdmsChannel(Names(11), TdmsDataType.Float) 'Inlet oil temp
      Dim ch12 As TdmsChannel = New TdmsChannel(Names(12), TdmsDataType.Float) 'Part temp
      Dim ch13 As TdmsChannel = New TdmsChannel(Names(13), TdmsDataType.String) 'Time stamp
      Dim Channels As TdmsChannelCollection
      Dim chans As TdmsChannel() = New TdmsChannel(13) {ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, ch13}
      Channels = channelGroup.GetChannels()
  
      ch0.UnitString = "RPM" : ch0.Description = "Rotational speed of the spindle shaft."
      ch1.UnitString = "CCM" : ch1.Description = "Oil flow from the specimen pump."
      ch2.UnitString = "Nm" : ch2.Description = "Torque from the torque cell."
      ch3.UnitString = "mm" : ch3.Description = "Linear displacement of the linear velocity displacement transducer."
      ch4.UnitString = "mm" : ch4.Description = "Linear displacement of the linear potentiometer."
      ch5.UnitString = "BIT" : ch5.Description = "Binary state of the pneumatic actuator (0=OFF, 1=ON)."
      ch6.UnitString = "BIT" : ch6.Description = "Binary state of the electric actuator (0=OFF, 1=ON)."
      ch7.UnitString = "BIT" : ch7.Description = "Binary state of the hydraulic actuator (0=OFF, 1=ON)."
      ch8.UnitString = "°F" : ch8.Description = "Upper tubular tank oil temperature."
      ch9.UnitString = "°F" : ch9.Description = "Lower (main) tank oil temperature."
      ch10.UnitString = "°F" : ch10.Description = "Thermocouple (Location: Remote rack, EL3318, Ch.2)."
      ch11.UnitString = "°F" : ch11.Description = "Thermocouple (Location: Remote rack, EL3318, Ch.3)."
      ch12.UnitString = "°F" : ch12.Description = "Thermocouple (Location: Remote rack, EL3318, Ch.1)"
      ch13.UnitString = "nS" : ch13.Description = "Time when the data was captured."
  
      'The only TDMS channels that get added to the collection are the ones that the user selects on the 'Configure Data File' form.
      'That is what this If-Then block is for. 
      If Channels.Count = 0 Then
          jArray.Clear()
          plcArrayNames.Clear()
          For Each [boolean] In bools
              If [boolean] = True Then
                  Channels.Add(chans(i))
                  Channels = channelGroup.GetChannels 'new
                  jArray.Add(jaggedarray(i))
                  plcArrayNames.Add(dataArrayNames(i))
              End If
              i += 1
          Next
      End If
  
      'At this point, we are ready to write data to the TDMS file.
      'Establish the line of communication to the PLC so we can read the data arrays.
      Dim tcClient As New TwinCAT.Ads.TcAdsClient()
      Dim dataStreamRead As TwinCAT.Ads.AdsStream = New AdsStream
      Dim binaryReader As System.IO.BinaryReader = New BinaryReader(dataStreamRead)
  
      If Connectlocal = True Then
          tcClient.Connect(851) 'local
      Else : tcClient.Connect(AMSNetID, 851)
      End If
  
      While cbRecord.Checked = True
          b = tcClient2.ReadAny(DRHvar, GetType(Boolean)) 'read the handshaking variable from the PLC
          If b = False Then
              'This For loop reads the appropriate arrays in the PLC and then writes that data to the appropriate arrays here.
              'The arrays in here will eventually get written to the TDMS file.
              i = 0
              n = 0
              writingData = True
              For Each [string] In dataArrayNames
                  If dataArrayNames(n) = plcArrayNames(i) Then
                      hvar = tcClient.CreateVariableHandle("IO_HS.Data." &amp; dataArrayNames(n))
                      value = 0
                      returnValue = jArray(i).GetType
                      If returnValue.Name = "Single[]" Then
                          dataStreamRead.SetLength(jArray(0).Length * 4)
                          dataStreamRead.Position = 0
                          tcClient.Read(hvar, dataStreamRead)
                          For Each [element] In jArray(0)
                              jArray(i)(value) = binaryReader.ReadSingle()
                              value += 1
                          Next
                      ElseIf returnValue.Name = "Int64[]" Then
                          dataStreamRead.SetLength(jArray(0).Length * 8)
                          dataStreamRead.Position = 0
                          tcClient.Read(hvar, dataStreamRead)
                          For Each [element] In jArray(0)
                              jArray(i)(value) = binaryReader.ReadInt64()
                              value += 1
                          Next
                      ElseIf returnValue.Name = "String[]" Then
                          dataStreamRead.SetLength(jArray(0).Length * 32)
                          dataStreamRead.Position = 0
                          tcClient.Read(hvar, dataStreamRead)
                          For Each [element] In jArray(0)
                              stringVar = binaryReader.ReadChars(32)
                              lastValidNumber = Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(stringVar.LastIndexOf("0"), stringVar.LastIndexOf("1")), stringVar.LastIndexOf("2")), stringVar.LastIndexOf("3")), stringVar.LastIndexOf("4")), stringVar.LastIndexOf("5")), stringVar.LastIndexOf("6")), stringVar.LastIndexOf("7")), stringVar.LastIndexOf("8")), stringVar.LastIndexOf("9"))
                              If lastValidNumber &gt; 0 Then
                                  jArray(i)(value) = stringVar.Substring(0, lastValidNumber + 1)
                              Else
                                  jArray(i)(value) = "Invalid Timestamp"
                              End If
                              value += 1
                          Next
                      End If
                      tcClient.DeleteVariableHandle(hvar)
                      i += 1
                      If i = plcArrayNames.Count Then
                          Exit For
                      End If
                  End If
                  n += 1
              Next
  
              'This For loop appends/writes the data from each array to the actual TDMS file.
              i = 0
              For Each [array] In jArray
                  dtype = Channels(i).GetDataType
                  If dtype.Name = "Int32" Then
                      Channels(i).AppendData(Of Integer)(jArray(i))
                  ElseIf dtype.Name = "Single" Then
                      Channels(i).AppendData(Of Single)(jArray(i))
                  ElseIf dtype.Name = "Boolean" Then
                      Channels(i).AppendData(Of Boolean)(jArray(i))
                  ElseIf dtype.Name = "String" Then
                      Channels(i).AppendData(Of String)(jArray(i))
                  End If
                  i += 1
              Next
  
              Try
                  'Call the DataAnalyzer dll to write stats of the cycle to stats CSV file.  Also plot the data of the cycle on the chart on the UI
                  Invoke(Sub() DataAnalyzer.Analyze(arrSpeed, arrTorque, arrLinPot))
                  Invoke(Sub() plotData())
                  Invoke(Sub() DataAnalyzer.WriteData(statsFile, logFile.Path, arrTimeStamp(0), plcData.cyclesCompleted))
              Catch ex As Exception
                  testBool = True
              End Try
  
              'Populate the datagridview cells with the data values
              dgvStats.Item(1, 0).Value = DataAnalyzer.peakTorque
              dgvStats.Item(1, 1).Value = DataAnalyzer.engagementSpeed
              dgvStats.Item(1, 2).Value = DataAnalyzer.slidePlateSpeed
              dgvStats.Item(1, 3).Value = plcData.bimbaTravSpeed
              dgvStats.Item(1, 4).Value = plcData.lastCycleTime
              dgvStats.Item(1, 5).Value = plcData.currentCycleTime
              dgvStats.Item(1, 6).Value = plcData.meanCycleTime
              dgvStats.Item(1, 7).Value = plcData.cyclesPerHr
  
              'NEW CODE to Evalute the elements in the arrTorque array to get the Max value recorded
              maxValue = 0
              For Each [element] In arrTorque
                  maxValue = Math.Max(maxValue, element)
              Next
              If maxValue &lt;= plcData.torqueAlrmSP And plcData.cycleStarted Then
                  torqueLowCount += 1
              Else : torqueLowCount = 0
              End If
  
              'Let the PLC know that we received the data and are now ready for the next set (handshaking variable).
              tcClient2.WriteAny(DRHvar, True)
          End If
  
          'If the data count in the first column of the TDMS file exceeds the number here, then
          'close the file and create a new one, then continue to append/write data
          If Channels(0).DataCount &gt;= 1020000 Then
              For Each channel As TdmsChannel In chans
                  channel.Dispose() : channel = Nothing
              Next
              chans = Nothing
              channelGroup.Dispose() : channelGroup = Nothing
              If tcClient.IsConnected Then
                  dataStreamRead.Dispose() : dataStreamRead = Nothing
                  tcClient.Disconnect() : tcClient.Dispose() : tcClient = Nothing
              End If
              'Jump to the CreateNewFile Sub to create the next TDMS file
              CreateNewFile()
          End If
      End While
  
      If logFile.IsOpen = True Then
          logFile.Close()
      End If
      If tcClient.IsConnected Then
          dataStreamRead.Dispose() : dataStreamRead = Nothing
          tcClient.Disconnect() : tcClient.Dispose() : tcClient = Nothing
      End If
      writingData = False
  End Sub
  
  Private Sub CreateNewFile()
      'Create the new folder where the data file/s will reside
      Dim newFilename As String = dataFileName &amp; "_" &amp; fileNum
      Dim customFilePropertyNames() As String = {"Date"}
      Dim customFilePropertyVals() As String = {""}
      Dim newAuthor As String = logFile.Author
      Dim newDescription As String = logFile.Description
      Dim newTitle As String = logFile.Title
      Dim newPath1 As String = "C:\Users\dmckin01\Desktop\Data\" &amp; folderName
      Dim newPath2 As String = "D:\Data\" &amp; folderName
      fileNum += 1
  
      'Create the TDMS file and save it to the user specified directory
      customFilePropertyVals(0) = Date.Today.ToShortDateString()
      logFile.Close() 'Close the old logfile after we've gotten values/properties from it
      logFile.Dispose() : logFile = Nothing
  
      Try
          If Connectlocal = True Then
              logFile = New TdmsFile(newPath1 &amp; "\" &amp; newFilename &amp; ".tdms", New TdmsFileOptions())
          Else : logFile = New TdmsFile(newPath2 &amp; "\" &amp; newFilename &amp; ".tdms", New TdmsFileOptions())
          End If
      Catch ex As Exception
          MessageBox.Show("Directory not created.  Make sure the TDMS file and/or directory that you are referencing are not already currently opened.", "Directory Creation Failed", MessageBoxButtons.OK, MessageBoxIcon.Error)
          Exit Sub
      End Try
      logFile.Author = newAuthor
      logFile.Description = newDescription
      logFile.Title = newTitle
      logFile.AddProperty(customFilePropertyNames(0), TdmsPropertyDataType.String, customFilePropertyVals(0))
      logFile.AutoSave = True
      dataAcquiring()
  End Sub
  </code></pre>