【问题标题】:Memory leak in VB file readerVB文件阅读器中的内存泄漏
【发布时间】:2012-05-16 10:40:45
【问题描述】:

我目前正在为 VB 中的固定宽度表格编写文件阅读器,编译后的应用程序似乎正在耗尽内存,就像没有明天一样。我正在处理一系列约 50 兆字节的文件,但在运行了几个文件后,该进程开始占用大约 200 多兆字节的 RAM,这远远超出了应有的范围。

我做了一些探索,我认为问题在于对 NewRow() 的调用,但不要相信我的话。

有没有人有一些优化这个的技巧?如果问题出在 NewRow() 调用上,有没有办法解决这个问题?

代码如下:

Function LoadFixedWidthFileToDataTable(ByVal filepath As String, ByRef Colnames() As String, ByRef colwidth() As Integer) As DataTable

    Dim filetable As New DataTable
    For Each name As String In Colnames
        filetable.Columns.Add(name)
    Next

    Dim loadedfile As StreamReader
    Try
        loadedfile = New StreamReader(filepath)
    Catch io As IOException
        MsgBox(io.Message)

        Return Nothing
        Exit Function
    End Try

    Dim line As String = loadedfile.ReadLine
    Dim filerow As DataRow = filetable.NewRow
    Dim i As Integer = 0

    While Not loadedfile.EndOfStream
        line = loadedfile.ReadLine
        filerow = filetable.NewRow
        i = 0


        For Each colsize As Integer In colwidth
            Try
                filerow(i) = line.Substring(0, colsize)
                line = line.Remove(0, colsize)
            Catch ex As ArgumentOutOfRangeException ''If the line doesn't match array params
                Exit For
            End Try
            i = i + 1
        Next
        filetable.Rows.Add(filerow)
    End While

    loadedfile.Close()
    Return filetable
End Function

【问题讨论】:

    标签: vb.net memory-leaks


    【解决方案1】:

    米库尔斯基,

    我马上就发现了一个问题。您正在调暗 Stream 阅读器。您应该将其包含在 using 块中,或者确保在每个代码路径的末尾添加 .Dispose。任何实现IDisposable 接口的东西都应该在 using 块中处理或使用,如下所示:

        Using fs As New FileStream("C:\testing.txt", FileMode.Open)
            Using sr As StreamReader = New StreamReader(fs)
                Dim message As String = sr.ReadLine()
                MessageBox.Show(message)
            End Using
        End Using
    

    希望对你有帮助,

    谢谢!

    编辑:

    以下是您的代码未处理的实现 IDisposable 的项目:

    • 数据表
    • StreamReader

    希望对你有帮助,

    再次感谢!

    这是一个占用内存较少的函数:

    Function LoadFixedWidthFileToDataTable(ByVal filepath As String, ByRef Colnames() As String, ByRef colwidth() As Integer) As DataTable
        Dim filetable As New DataTable
        Try
            For Each name As String In Colnames
                filetable.Columns.Add(name)
            Next
    
            Try
                Using loadedfile As StreamReader = New StreamReader(filepath)
                    Dim line As String = loadedfile.ReadLine
                    Dim filerow As DataRow = filetable.NewRow
                    Dim i As Integer = 0
    
                    While Not loadedfile.EndOfStream
                        line = loadedfile.ReadLine
                        filerow = filetable.NewRow
                        i = 0
    
                        For Each colsize As Integer In colwidth
                            Try
                                filerow(i) = line.Substring(0, colsize)
                                line = line.Remove(0, colsize)
                            Catch ex As ArgumentOutOfRangeException
                                Exit For
                            End Try
                            i = i + 1
                        Next
    
                        filetable.Rows.Add(filerow)
                    End While
    
                    loadedfile.Close()
    
                End Using
            Catch io As IOException
                MsgBox(io.Message)
    
                Return Nothing
            End Try
            Return filetable
        Catch ex As Exception
            filetable.Dispose()
        End Try
    
        Return Nothing
    End Function
    

    我注意到您正在退回您应该处理的东西。如果你这样做,你不能在这里处理它。相反,调用这个函数的地方必须处理它。如果您在此周围包装 using 块,您将遇到问题,因为返回的对象将在您有机会从调用代码对其进行操作之前被处置。

    希望对你有帮助,

    再次感谢!

    【讨论】:

    • 谢谢!我猜外部调用应该看起来像 Using ThisTable as Datatable = LoadFixedwidthFiletoDatatable() ...stuff... End Using 应该负责处理,或者我应该调用 ThisTable.Dispose(),只是为了安全吗?
    • 调用 Dispose 更加明确,但如果您的代码使用“Using”块,则不需要。当您的代码退出“使用”块时,它会为您调用 dispose 函数。因此,例如,如果您的代码启动了一个 Using 块,出现错误,并从 using 块“跳出”到异常处理程序,那么它将调用 Dispose 方法。但是,通过函数调用“跳出”使用块是可以的,因为您将返回到调用代码。即使这样,如果函数中发生异常,你会没事的,因为代码将遍历堆栈并正确退出 using 块。
    • 刚刚通过 perfmon 检查了一个测试运行;效果很好!再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多