none
DataTable.NewRow causes OutOfMemory RRS feed

  • Question

  • Hi everyone,

    This code:

      Sub Main()
        Dim myDT As New DataTable
    
        While True
          Dim myRow = myDT.NewRow
        End While
      End Sub
    

    ... will cause an OutOfMemory exception. According to the Internets, the only way to let new rows die a good death is by either adding then deleting them from the DataTable, or to call DataTable.Clear. Neither solutions work for me because I may not have a reference to my new row when I need it (and it is impossible to retrieve references to non-added new rows), and my DataTable has some rows I actually need, so clearing indiscriminately will get rid of those too.

    Any ideas?

    Friday, October 22, 2010 7:03 PM

Answers

  • Ah, ok ... I see what you're trying to do now. You could use a clone of your DataTable for those temporary new rows:

    Dim myDT As MyDataTable.Clone()
    Dim myRow = myDT.NewMyDataTableRow
    
    

    Clone will create a copy of the schema only, not the data.


    ~~Bonnie Berent [C# MVP]

    geek-goddess-bonnie.blogspot.com
    Monday, October 25, 2010 2:18 PM

All replies

  • What exactly do you wish to accomplish? Of course the code you posted will cause an OutOfMemory exception ... you're in an infinite loop!!! It will never end until you run out of memory.

    So, tell us what you want to do ... then we can direct you to a solution to your problem.


    ~~Bonnie Berent [C# MVP]

    geek-goddess-bonnie.blogspot.com
    Saturday, October 23, 2010 3:00 PM
  • Infinite loops do not create OutOfMemory. For example this code:

      Sub Main()
        Dim myRandom = New Random
        While True
          Dim myInt = myRandom.Next
        End While
      End Sub
    

    ... will run until the sun goes dark and stay at a cool 18megs of memory forever. My point is myInt goes out of scope and is GCed, whereas myRow in the previous example is never GCed, because DataTable.NewRow creates an object that can never be GCed unless the previously mentionned workarounds - which I cannot use - are applied.

    What I'm really trying to do is to cache temporary values (in my case, DataContract objects that I deserialize in typed DataSets prior to validation) in NewRows, but that quickly makes my server blow up as the temporary rows are never collected, even after they go out of scope.

    Monday, October 25, 2010 1:06 PM
  • Ah, ok ... I see what you're trying to do now. You could use a clone of your DataTable for those temporary new rows:

    Dim myDT As MyDataTable.Clone()
    Dim myRow = myDT.NewMyDataTableRow
    
    

    Clone will create a copy of the schema only, not the data.


    ~~Bonnie Berent [C# MVP]

    geek-goddess-bonnie.blogspot.com
    Monday, October 25, 2010 2:18 PM
  • That's very interesting. This code:

      Sub Main()
        Dim myPermanentDT As New DataTable
        While True
          Dim myClone = myPermanentDT.Clone
          Dim myTempRow = myClone.NewRow
        End While
      End Sub
    

    stabilizes its memory usage very quickly. However this code:

      Sub Main()
        Dim myTypedDS = New TypedDataSet
        While True
          Dim myClone = myTypedDS.Orders.Clone
          Dim myRow = myClone.NewRow
        End While
      End Sub
    

    shows an ever-increasing memory footprint. Analyzing where this memory is held up requires tools that I do not have right now, and will aquire should this problem persist. The rate at which memory goes up is far lower then my first example however. I think the rate is low enough that I can convince my users to restart the server every now and then. It isn't perfect, but unless anyone else can give me a proper way to allow NewRows to be collected, I will use your idea, and mark your post as the answer.

    Monday, October 25, 2010 3:28 PM
  • I don't see why it should make any difference, but try it this way instead and see if you still get the increasing memory:

    Sub Main()
      Dim myTypedDS = New TypedDataSet
      Dim dtOrders = myTypedDS.Orders
      While True
       Dim myClone = dtOrders.Clone
       Dim myRow = myClone.NewRow
      End While
     End Sub
    
    

    ~~Bonnie Berent [C# MVP]

    geek-goddess-bonnie.blogspot.com
    Monday, October 25, 2010 3:38 PM
  • No dice. Same result. I'm very curious to know what is referencing this memory. Could it be that myTypedDS keeps a reference to all cloned datatable schemas? That seems very unlikely to me, yet is the first answer that comes to mind. Alternatively, it could be that all objects are being collected properly, and that the memory I'm watching only goes up because of some feature of the GC I do not understand. Wouldn't be the first time. Regardless, your solution does not throw any OutOfMemory even after an hour of infinite looping, which is far more intense that any real-life scenarios I can foresee. I will leave this ticket unsanswered for the week, in hope that we can get some more insight on DataSet, NewRow and the GC, but next week I will close it as answered either way.

    Thanks for your time and expertise.

    Monday, October 25, 2010 3:56 PM
  • Here's an interesting tidbit: I suspended my infinite loop randomly and got this call stack:

      mscorlib.dll!System.GC.SuppressFinalize(object obj) + 0x11 bytes 
      System.Data.dll!System.Data.DataTable.DataTable() + 0x146 bytes 
      System.Data.DataSetExtensions.dll!System.Data.TypedTableBase<System.__Canon>.TypedTableBase() + 0x5 bytes 
      ConsoleApplication1.exe!ConsoleApplication1.TypedDataSet.OrdersDataTable.New() Line 287 + 0x9 bytes Basic
      ConsoleApplication1.exe!ConsoleApplication1.TypedDataSet.OrdersDataTable.CreateInstance() Line 424 + 0x15 bytes Basic
      System.Data.dll!System.Data.DataTable.Clone(System.Data.DataSet cloneDS = null) + 0x4c bytes 
      System.Data.dll!System.Data.DataTable.Clone() + 0x7 bytes 
      ConsoleApplication1.exe!ConsoleApplication1.TypedDataSet.OrdersDataTable.Clone() Line 417 + 0x8 bytes Basic
      ConsoleApplication1.exe!ConsoleApplication1.Module1.Main() Line 8 + 0x8 bytes Basic

    Somewhere in the DataTable.Clone call, some object is being suppressed. How odd.

    Monday, October 25, 2010 4:33 PM
  • Hmmm ... well, I'm not much of an expert when it comes to the GC, so I don't exactly know what the implications of that are. It still seems weird to me that the clone would have anything to do with the DataTable it was cloned from ... if indeed that is what's implied from all this.

    Interesting topic ... it would be nice if we'd get some feedback from someone who knows more about the GC than we do.


    ~~Bonnie Berent [C# MVP]

    geek-goddess-bonnie.blogspot.com
    Monday, October 25, 2010 4:42 PM