1

As the title suggests, I was wondering if using DataTable (or any object-type) as a parameter or return value causes memory leaks? Suppose I have 3 different functions:

public DataTable InitDT()
{
    //Create and Initializes the dataTable columns, and returns a DataTable
    DataTable dt = new DataTable();
    DataColumn column = new DataColumn();
    column.ColumnName = "Id";
    dt.Columns.Add(column);
    return dt;
}

public DataTable PopulateDT()
{
    //Populate an Initialized DataTable and return it
    DataTable dt = InitDT();
    DataRow row;
    row = dt.NewRow();
    dt.Rows.Add(row);
    return dt;
}

public void ReadDT()
{
    //Read return DataTable
    DataTable dt = PopulateDT();
    foreach (DataRow r in dt.Rows)
    {
        txtId.text = r[0].ToString();
    }
    dt.Dispose();
}

On my code, only the last function calls dt.Dispose(); so I was wondering what happens to the 2 previously created DataTables. Does the garbage collector already cleans them?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
JayzeeNSI
  • 31
  • 1
  • 7

2 Answers2

1

There won't be any memory leak as ADO.NET objects use no unmanaged resources.

The Dispose method of DataTable is inherited from MarshalByValueComponent, which to DataTable does nothing.

weichch
  • 9,306
  • 1
  • 13
  • 25
  • Based on the link, It's ok that I should not call dispose at all? And also, off-topic but SQLite connection can be disposed too? – JayzeeNSI Mar 29 '20 at 20:24
  • @JayzeeNSI You should call `Dispose` regardless of its implementation when you could. And that's what the guideline says despite it doing nothing. It is just when you fail to call `Dispose`, such as an exception is thrown from `PopulateDT` which makes `ReadDT` not called, you don't have a memory leak. In terms of connections, they might hold underlying TCP connections that are unmanaged resources, so I'd definitely call `Dispose`. – weichch Mar 29 '20 at 20:44
  • Is closing an open SQLite connection be enough? Or is there a Dispose call I'd need to call? – JayzeeNSI Mar 29 '20 at 21:06
  • There should be `Dispose` method on connection. Calling `Dispose` usually close and release connection. – weichch Mar 29 '20 at 21:17
  • @[weichch](https://stackoverflow.com/users/10620317/weichch) So, if I call `con.Dispose()`, does that mean I don't need to call `con.Close()` because it is already released? – JayzeeNSI Mar 30 '20 at 01:53
  • If you call `Dispose`, you don't need to call `Close`. `Dispose` should call `Close` internally. – weichch Mar 30 '20 at 01:59
0

1) Strictly speaking, you cannot get a memory leak in C#.

This requires some explanation:

Firstly, that assumes you are dealing purely in managed code. If you C# connects to any unmanaged code, then you can get memory leaks there, but not in the C# itself. There is no unmanaged code here.

Secondly, a C# program can certainly deallocate less memory than it should, but strictly speaking it's not a memory leak. A memory leak occurs when the program loses all references to the memory, but the memory is still allocated. This can't happen in C#. What can happen is you accidentally keep hold of references that you don't need (e.g. filling up references in a List and not clearing out the ones you've finished with). Again, that's not happening here.

Thirdly, the purpose of Dispose is not to clean up memory, but to clear up resources other than memory, e.g. file handles, DB connections and unmanaged resources (see above).

So by missing Dispose, you could have a resource leak, but not a memory leak.

2) Whether you get a resource leak depends on context

ReadDT is self-contained - it creates (indirectly) and disposes of DataTable and returns nothing. The only problem is the is should have a using block to call the Dispose to guarantee its called when exceptions are thrown.

The other two methods both create (directly or indirectly) a DataTable and return it. They correctly do not Dispose it, because if they did they'd be returning a disposed object, which should not be used by anyone.

The general rule is then, if a method creates and returns a disposable object, the assumption is that it is the responsibility of the caller to dispose it (as is done in ReadDT) or to defer the responsibility to somewhere else, typically by returning the object, as is done by the other two methods.

Jasper Kent
  • 3,546
  • 15
  • 21
  • You can have memory leak in pure C# code. For example, an object is referenced by an event handler which is not detached correctly. This can stop GC from collecting the object causing a memory leak. – weichch Mar 29 '20 at 11:05
  • If the GC can't collect an object, the the object must be referenced, by some route, from either the stack of static memory. The event handler example you give a problem, but not strictly a memory leak. It's similar to the `List` example (though perhaps a more realistic example) – Jasper Kent Mar 29 '20 at 11:08
  • I seem to have a different understanding of memory leak here. The list example is not a memory leak to me only if my code still has access to the list and I can still clear the list if I want to. However, if the list is caught in an unknown object which my code does not have access to, I may call it a memory leak as long as GC can't collect it and memory consumption keeps going up. – weichch Mar 29 '20 at 11:19
  • If your code does not have access, the GC will collect. That's how it works out what to collect. The problem is that your code may have access without you realizing it. – Jasper Kent Mar 29 '20 at 11:23
  • I agree with you if both objects have same lifetime then GC can work. I was thinking something else, like inside constructor of a class, the instance is added to a list which my code doesn't have access to, and the list is held in a static context. The class exposes a Dispose method which removes the instance from the list, but I forgot to call. If my code exits the context where the instance exists, I will not be able to remove it from the list, and this to me is a memory leak. – weichch Mar 29 '20 at 11:57
  • Thanks for this detailed info. Is there any guide to avoid resource leaks? and also, since the functions returns a disposable obj, does that mean that what they actually return is a pointer to that DataTable, instead of the DT? Based on my understanding, The receiver of the function handles the Dispose of DT, so the Same DT that was created from InitDB is the same as the one that's Disposed in ReadDT. – JayzeeNSI Mar 29 '20 at 20:19
  • @JayzeeNSI Yes, all the functions return a *reference* to the `DataTable` (strictly speaking, reference is the correct term, though conceptually they are very like pointers). There's only ever been one `DataTable` created (`new DataTable();` in `InitDT`) so `Dispose` should only ever be called o it once. – Jasper Kent Mar 29 '20 at 21:21
  • @[Jasper](https://stackoverflow.com/users/2667528/jasper-kent) Thanks for the info!. I'm just thinking the performance of my program if I say, I run simultaneous queries that each returns >1000 Rows. This info is a relief so now I know that only the 'reference' to that object has been returned. And I call it 'pointer' cause I mainly use Java. – JayzeeNSI Mar 30 '20 at 01:58