Possible Memory Leak in MySQL connection

Possible Memory Leak in MySQL connection

Postby vincentfitzg » Fri 25 Jan 2008 11:57

Hi,
We have memory problems in a multithreaded application. We create a number of threads to read a number of large blobs (4-20MB each) from the database. The memory rises sharply at the beginning but never goes down to the orignal level.
A memory profiler shows that the memory is in a byte array in the MySQlInternalConnection. Even after closing and disposing the connection the memory remains the same. It looks as if the connection is keeping a reference to the data that was read out last.

We are using version 3.5, I have downloaded the latest trial version 4.30 as well and get the same results. Developing using Visual Studio 2005 .

I have attached code below, I can also send a test database when required.

can you let me know if there is something wrog

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using CoreLab.MySql;
using System.Threading;
using System.Collections;
using System.Diagnostics;
namespace WindowsApplication4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

static MySqlConnection GetConnection()
{
string connectionString;
connectionString = "server = localhost;";
connectionString += "database = Test DB;";
connectionString += "user id = root;";
connectionString += "pwd=;";

MySqlConnection connection = null;

try
{
connection = new MySqlConnection( connectionString );
}
catch
{
connection.Dispose();
connection = null;
return null;
}

try
{
connection.Open();
}
catch
{
if( connection != null )
{
connection.Dispose();
connection = null;
}
return null;
}
return connection;
}
private long GetMemory()
{
long page = Process.GetCurrentProcess().PagedMemorySize64 / 1024;
long ram = Process.GetCurrentProcess().WorkingSet64 / 1024;

long total = page + ram;

return total;
}
private void button1_Click( object sender, EventArgs e )
{

ArrayList threads = new ArrayList();
Thread thread;

long startmem = GetMemory();

for( int i = 0; i < 5; i++ )
{
thread = new Thread( new ThreadStart( ReadStuff ) );
thread.Name = "Frames Read Thread:" + i;
thread.Start();
threads.Add( thread );
}

foreach( Thread thr in threads )
thr.Join();

GC.Collect();
long endmem = GetMemory();
label1.Text = "Initial Memory :" + startmem + " Final Memory :" + endmem + " Diff: " + (endmem - startmem);

}
private static void ReadStuff()
{
MySqlConnection connection = GetConnection();

if( connection == null || connection == null )
return;

string com = "SELECT Object FROM FrameSpecifics WHERE InspectionIndex=1";

using( MySqlCommand command = new MySqlCommand( com ) )
{
command.Connection = connection;
try
{
using( MySqlDataReader reader = command.ExecuteReader( System.Data.CommandBehavior.SingleResult ) )
{
while( reader.Read() && reader.FieldCount > 0 )
{
using( MySqlBlob mySqlBlob = reader.GetMySqlBlob( 0 ) )
{
if( mySqlBlob != null && mySqlBlob.Value != null )
mySqlBlob.Dispose();
}
}
}
}
catch( Exception ex )
{
Console.WriteLine("Error:" + ex.Message);
}
}
connection.Close();
connection.Dispose();
connection = null;
GC.Collect();
}
}
}
vincentfitzg
 
Posts: 10
Joined: Wed 27 Jul 2005 11:36

Postby Alexey.mdr » Fri 25 Jan 2008 12:26

Actual connection is not closed in order to be used later by your application. This is Connection Pooling feature in many cases this boosts performance greatly.
You can clear the pool explicitly. Generally pool is cleared automatically when connections are idle or closed by server. To force the operation call ClearPool or ClearAllPools methods. Another solution is to disable the pool at all (set Pooling=false in connection string). Please let us know, if this doesn't help.
Alexey.mdr
 
Posts: 729
Joined: Thu 13 Dec 2007 10:24

Postby vincentfitzg » Fri 25 Jan 2008 14:31

Hi Alexey,
Thanks for the quick reply. I figured that it might have something to do with the connection pooling. I tried the ClearAllPools method and it does improve the memory situation but I would still like to use the connection pool, since it does increase the performance. And speed is very important for our application.

I understand that there is a list of previous connections stored for the pool to be used later, but what I dont understand is why they have a reference to so much data. If i create five threads and therefore five connections it will lose up to 50MB in memory. This cant just be memory to store pooled connections?
If i use the same code and return an index instead of the blob, then little or no memory is lost.

Thanks for your help
vincentfitzg
 
Posts: 10
Joined: Wed 27 Jul 2005 11:36

Postby Alexey.mdr » Fri 25 Jan 2008 16:18

A special buffer allocates space in managed heap when you open a connection. The size of the buffer depends on the amount of bytes being transmitted. Hence if you open a connection and send BLOB files, the size of the buffer is going to be quite big. Then you close this connection, and despite of being garbage-collected, it moves to Connection Pool.
Next time you want to open a connection, it is going to be fetched from the pool. The system will not allocate memory again.
What you need to do is to play around with connection pooling to find a balance between speed and size.
Alexey.mdr
 
Posts: 729
Joined: Thu 13 Dec 2007 10:24


Return to dotConnect for MySQL