2

I am using C# and an OBDC DSN to connect to a Paradox database. I seem to be leaking memory if I open and close each connection.

My code is basically:

            csb.Dsn = "DNSName";
            OdbcConnection con = new OdbcConnection(csb.ConnectionString);
            con.Open();

            OdbcCommand comm= new OdbcCommand("SELECT * FROM Tabl", con);
            OdbcDataReader reader= null;
            try
            {
                reader= comm.ExecuteReader();
                for (int count = 0; (count < 5 && reader.Read()); ++count)
                {
                    //Read
                }
            }
            finally
            {
                if (reader!= null)
                {
                    reader.Close();
                    reader.Dispose();
                }
                if (comm!= null)
                {
                    con.Close();
                    con.Dispose();
                    OdbcConnection.ReleaseObjectPool();
                    GC.Collect();
                    comm.Dispose();
                }
            }

Any ideas or suggestions?

Update 1

I changed it to use using statments, still leaks.

Anthony D
  • 10,877
  • 11
  • 46
  • 67
  • If **comm** were ever null, you would not close your connection. I don't see how that could happen here, but you probably want to check of **con** is not null and close/dispose it rather than checking **comm**. Also, suggest you take a look at the *using* keyword. – Eric J. Aug 25 '09 at 16:45
  • What are you using to determine that your application is leaking memory? – Adam Hughes Aug 25 '09 at 18:57
  • The memory usage climbs constantly, and quickly, then when I stop all threads, it never returns to a base line, or comes down at all. – Anthony D Aug 26 '09 at 14:34
  • What kind of Paradox ODBC driver are you using? GC.Collect shouldn't be necessary. – Yvo Feb 18 '10 at 19:54
  • Wow, so this is an old thread, but I'm having the same issue - using blocks don't fix the problem. Anyone have any fresh ideas, or did OP find a solution? – xdumaine Aug 05 '10 at 20:00
  • I never worked on the Paradox odbc drivers, but I know the Access drivers used to always leak memory. You'd have to reboot your server every night. – mwgriffith Aug 06 '10 at 00:58

4 Answers4

3
using (var connection = new OdbcConnection(csb.ConnectionString))
{
    connection.Open();
    using (var command = new OdbcCommand("SELECT * FROM Tabl", connection))
    using (var reader =  command.ExecuteReader())
    {
        for (var count = 0; (count < 5 && reader.Read()); ++count)
        {
            //Read
        }
    }
}
OdbcConnection.ReleaseObjectPool();

There is no memory leak in the above code, unless it is created at the "// Read" excecution point. GC.Collect should not be used in production ever; it most likely won't help anyway and may actually hinder the GC as it's self-tuning. Grab a profiler (or a free trial of one) like ANTS Memory Profiler and see what is hanging on to your objects.

Do not trust the Windows Task Manager to show you whether you have leak. Make sure to use a profiler for that purpose.

Travis Heseman
  • 11,359
  • 8
  • 37
  • 46
2

Try putting the connection, command, and reader inside of using statements.

Then call OdbcConnection.ReleaseObjectPool(); at the end.

Note: it may take a few minutes for garbage collection to run. To prove that there is no leak you could call GC.Collect() three times in a row [three times to clear out objects through all three generations].

Do not leave the GC.Collect() in production code though because it can become a big performance hit.

Michael Haren
  • 105,752
  • 40
  • 168
  • 205
TimW
  • 89
  • 3
0

How did you detect the leak? Sometime mem usage goes up in task manager and not release immediately may due to GC not kicking in straightaway or you have connection pool or handle that havent yet been released in the managed environment. I suggest that you use memory profiler like ANTS Mem Profiler suggested by Travis. You can get a trial version, otherwise use basic version by Microsoft CLRProfiler.

Another good measure if to load the process so that it runs longer during the profiling process so that if there is problem, it will clearly shown. The easiest is to put a loop around it so that say run the above for 1000 times or more. You can also use performance monitor to monitor some of the counter of interest and see how they trace during the execution.

Fadrian Sudaman
  • 6,405
  • 21
  • 29
0

Try to avoid calling GC.Collect

Never touch the garbage collector unless you are 100% sure you know what you're doing. Always remember - the garbage collector is smarter than you, and it knows the best time to run.