简体   繁体   中英

ADODB in C# leaks memory

In my application I'm using ADODB to query a MySQL database. This goes very smooth, however, ADODB seems to leak a lot of memory.

I fixed it partially by calling the close method of every executed query.
I found out by benchmarking 1000000 queries on this method:

public static int Execute(string query)
{
    Connect();
    object ret;
    lock (_conn)
        _conn.Execute(query, out ret, -1);
    return (int)ret;
}

After a about 10000 queries I was out of memory, extremely fast.

I figured it was because of the _conn.Execute, so I changed it into:

public static int Execute(string query)
{
    Connect();
    object ret;
    ADODB.Recordset rs;
    lock (_conn)
        rs = _conn.Execute(query, out ret, -1);
    rs.Close();
    return (int)ret;
}

Now, this seems to save a lot but it still leaks about 80MB of memory after executing 100000 queries.

Does anyone know how to stop it from leaking memory, I do NOT need the recordset. I have 3 different functions, one for executing like this, one for executing and returning a recordset wrapped in my own classes, and one for executing and returning the last inserted id, useful for INSERT INTO queries.

So, does anyone know how to stop the leak?

EDIT :

This is the code in Connect():

private static ADODB.Connection _conn = new ADODB.Connection();

public static bool Connected
{
    get { return _conn.State == 1; }
}

public static bool Connect()
{
    lock (_conn)
        if (!Connected) _conn.Open(Configuration.DB_ConnectionString, "", "", -1);
    return Connected;
}

When working with COM from .Net, you need to explicitly release any handles to COM objects you've used, otherwise they'll stay in memory forever.

System.Runtime.InteropServices.Marshal.ReleaseComObject( obj );

So to rewrite your code:

object ret;
ADODB.Recordset rs = null;

Connect();

try
{
    // Why the lock? Is your code sharing the same connection across threads?
    lock (_conn) 
        rs = _conn.Execute(query, out ret, -1);

    rs.Close();
}
finally
{
    if (rs != null)
        System.Runtime.InteropServices.Marshal.ReleaseComObject( rs );
}

return (int)ret;

You will need to protect _conn in the same way, ensuring you call ReleaseComObject when finished with it.

Have you considered using the MySql .Net Connector ? Given that it's a managed library which is designed specifically for connecting to MySql, it stands a better chance of not leaking. Also, I've used it previously and not noticed it leaking memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM