数据集和内存泄漏

时间:2013-04-01 21:00:49

标签: .net vb.net memory-management memory-leaks dataset

我正在尝试找出使用DataSet / DataTable的最佳方法,然后进行适当的清理。

我对释放内存的原因感到有些疑惑。我用一个测试应用程序测试了我的理论,我在一个循环中多次填充相同的DataTable并在3个强制GC收集后查看Windows的任务管理器以查找内存占用量。

我发现的是:

  1. 如果我没有拨打ClearDispose,或将DataTable变量设置为Nothing,则任务管理器中的最终内存消耗约为30k。

  2. 如果我只是将循环中的变量设置为Nothing,则最终内存大约为15k。 问题:为什么将变量设置为Nothing会产生影响?

  3. 如果我在循环中仅调用Dispose方法,则最终内存大约为19k。

  4. 如果我在循环中仅调用Clear,则最终内存大约为16.5k。事实上,即使在GC.Collect

  5. 之后,它也没有改变

    如果有人能够分享在不再需要时使用和清理DataSet的最佳方式,我将非常感激。

    示例代码如下所示。

    Imports System.Data.SqlClient;
    Public Class Form1
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            Test()
    
            GC.Collect()
            GC.Collect()
            GC.Collect() 'Throw in one more 
        End Sub
    
    
        Private Sub Test()
            Dim oDA As SqlDataAdapter = Nothing
            Dim oConn As SqlConnection = Nothing
            Dim oCommand As SqlCommand = Nothing
            Dim ods As DataSet = Nothing
            Dim oDt As DataTable = Nothing
            Try
                oConn = New SqlConnection("Server=Myserv;Database=myDB;UserId=myuserid;Password=mypassword;")
                oCommand = New SqlCommand("Select  * from Users", oConn)
                oConn.Open()
                ods = New DataSet
    
                oDA = New SqlDataAdapter(oCommand)
    
                For i As Integer = 0 To 50
                    oDA.Fill(ods)
                    oDt = ods.Tables(0)
                    'oDt.Clear()
                    'oDt.Dispose()
                    oDt = Nothing
                Next
            Catch ex As Exception
                MessageBox.Show(ex.ToString)
            Finally
                ods.Clear()
                ods = Nothing
                oConn.Close()
                oDA = Nothing
            End Try
        End Sub
    End Class
    

    编辑:我正在寻找管理传递的DataSet和/或DataTable内存的最佳实践,其中创建方法不一定要清理内存。另外,为什么在函数中将对象/变量设置为Nothing的方式不同于让它超出范围。

3 个答案:

答案 0 :(得分:5)

“清理”数据的最佳方法是切换到Using statement以获取实现IDisposable 1 的任何内容。实现此模式后,您将拥有最合理的内存使用量,用于您设计的数据结构

Using oConn As New SqlConnection("Server=Myserv;Database=myDB;UserId=myuserid;Password=mypassword;")
    oConn.Open()
    Using oCommand As New SqlCommand("Select  * from Users", oConn)
        ' other code as needed, wrap IDisposable in Using...EndUsing
    End Using
End Using

这并不能保证您的数据结构本身具有内存效率,只要它们只在必要时保留资源。

<子> 1。是的,你有时候不能使用一个,但是如果你在不使用using语句的前提下工作,你会更好。

答案 1 :(得分:0)

“为什么在一个函数中设置任何东西都不同于让它超出范围?”

您已经访问了某些内容,因此在此之前它不符合GC的条件。

当GC发生时有点不确定:显然它会根据几个因素安排下一次调用(引用:http://channel9.msdn.com/Shows/Defrag-Tools/Defrag-Tools-33-CLR-GC-Part-1(视频))。

答案 2 :(得分:0)

使用任何必须在使用后释放的资源(包括DataTable或Dataset)的最佳方法是尽可能使用关键字Using。如果无法使用Using关键字,则应该执行与使用关键字相同的操作: 尝试 { } Catch(Exception ex) { } 最后 {   object.dispose() }

根据msdn,任何实现IDisposable的对象都应该使用dispose方法释放资源。既可以使用Dataset,也可以使用 DataTable继承自实现IDisposable的MarshalByValueComponent,因此最好调用dispose方法。如果有 是任何不实现IDisposable方法的资源,那么您可以实现IDisposable接口并覆盖dispose 处理方法和资源清理方法。通过将DataSet或DataTable设置为null,您只需删除 最后将由垃圾收集器收集的引用。但使用dispose方法是更好的方法。你没有 显式调用GC.Collect方法,因为垃圾收集器通常在后台和内存中运行 如果低于某个阈值(由编译器确定),它将释放这些资源使用的内存。欲了解更多信息,请 请参阅垃圾收集(http://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspx