我正在对今天的应用程序进行故障排除,定期运行以处理一些数据处理需求,它通常运行得很好,但有时应用程序会崩溃,有人必须手动重启它。
在查看源代码并进行一些调试之后,程序的核心似乎依赖于递归函数,该函数从DataTable中删除行,然后在DataTable不再有任何行剩余时停止。
以下是代码:
Public Sub ProcessData(ByRef dtTable As DataTable)
Dim DataView1 As New DataView()
Dim UID As String = ""
Dim dtUID As New DataTable
dtUID = dtTable.Clone()
UID = dtTable.Rows(0)("UID")
DataView1 = dtTable.DefaultView
Dim expression As String = "UID ='" & UID & "'"
DataView1.RowFilter = expression
For n As Integer = 0 To DataView1.Count - 1
dtUID.ImportRow(DataView1.Item(n).Row)
Next
Dim foundRows() As DataRow
foundRows = dtTable.Select(expression)
For n As Integer = 0 To foundRows.GetUpperBound(0)
dtTable.Rows.Remove(foundRows(n))
Next
For n As Integer = 0 To dtUID.Rows.Count - 1
ProcessRecord(dtUID, n)
Next
If dtTable.Rows.Count > 0 Then
ProcessData(dtTable)
End If
End Sub
ProcessRecord()
是一个将所有业务逻辑应用于记录并对数据库进行写入的函数。未处理的堆栈overFlow异常发生在:
For n As Integer = 0 To DataView1.Count - 1
在现实世界中,此函数将被输入DataTable
,其中包含大约100,000条记录。在测试中,在堆栈溢出之前,经过多次试运行后,它将持续运行大约40,000-65,000。创建已经处理过的DataTable
和ProcessRecord()
标志记录的代码,因此如果您正在处理100,000个记录的大型数据集,则会在崩溃后对此方法进行后续调用较小的DataTable
(35,000-60,000条记录。)有趣的是,堆栈溢出将越来越频繁地发生DataTables
更小,我可以始终通过40k-65k的100k DataTable
但不能始终如一在没有崩溃的情况下获得15k的15k DataTable
(最终它将完成所有记录,在过去的几千次中发生多次崩溃。)
一旦我看到问题所在,我基本上废弃了大部分代码,并使用了我过去用于类似任务的实现。但我真的很想明白为什么这段代码导致了这个问题。
答案 0 :(得分:2)
问题在于它是一个递归函数。
每个函数调用都使用堆栈空间来存储其参数和局部变量,并且堆栈空间有限。
没有理由这个特定的操作应该是递归的。事实上,当无法轻易估计或限制最大递归次数时,使用递归解决方案是个坏主意。