Garbage Collection

  • Thread starter Thread starter Sharon
  • Start date Start date
S

Sharon

Hi,
I currently have a web service method which connects to an
Oracle database using ODP.Net. I am seeing connections
being held open for longer than I would expect them to be -
there seems to be some sort of handle left there when
everything else is done. I am seeing the
connections reach the set max pool size then give an
error. I then have to wait for garbage collection to run
(approx. ten minutes) before these handles are closed and
the connections are freed up. I've implemented a
workaround for this, whereby I force garbage collection
every time the web service is consumed (using gc.collect),
but this is not an ideal solution. If you have any
suggestions on how to get round this, I'd love to hear
them.

Thanks,
Sharon
 
Sharon,
Close the connection when you are done using it.

Aside:
If an object implements IDisposable, whatever it is, you should make
sure to call the Dispose() method on it. Note that sometimes the
method is only available if the object is cast to IDisposable, but for
(at least) an SqlConnection, the appropriate method to call is
Close().

Hope that is of some use,
Scott
 
Hi,

Thanks for your input. I already Close() the connection
and Dispose() of the objects where necessary so I'm a
little stumped as to what is causing this.

Sharon
 
Sharon said:
Hi,

Thanks for your input. I already Close() the connection
and Dispose() of the objects where necessary so I'm a
little stumped as to what is causing this.

Sharon

Unfortunately this has never been documented to happen except when
application code fails to close connections.

So how do you tell where your connection leak is?

Here's how:

Open your connections throgh the following ConnectionFactory class.
This will attach a "Connection Spy" to your connection object. On creation
the Conenction Spy records the current stack trace, so it knows what bit of
code opened the connection. The two objects will have references to each
other (one a regular reference, one an event handler delegate reference),
and so will be GC'd at the same time. The Connection Spy will then print
out a warning message to Trace if it's finalizer is running and the
connection has not been closed. This will produce a record of what method
opened a connection which was not closed.

David



using System;
using Oracle.DataAccess.Client;
using System.Diagnostics;
using System.Data;

namespace ConsoleApplication29
{


public class ConnectionFactory
{
private class ConnectionSpy
{
OracleConnection con;
StackTrace st;

public ConnectionSpy(OracleConnection con, StackTrace st )
{
this.st = st;
//latch on to the connection
this.con = con;
con.StateChange += new StateChangeEventHandler(StateChange);
}
public void StateChange(Object sender ,
System.Data.StateChangeEventArgs args)
{
if (args.CurrentState == ConnectionState.Closed )
{
//detach the spy object and let it float away into space
//if the connection and the spy are already in the
FReachable queue
//GC.SuppressFinalize doesn't do anyting.
GC.SuppressFinalize(this);
con.StateChange -= new
StateChangeEventHandler(StateChange);
con = null;
st = null;
}
}
~ConnectionSpy()
{
//if we got here then the connection was not closed.
Trace.WriteLine("WARNING: Open Connection is being Garbage
Collected");
Trace.WriteLine("The connection was initially opened " +
st.ToString());
}
}

public static OracleConnection OpenConnection(String Connect)
{
OracleConnection con = new OracleConnection(Connect);
con.Open();
StackTrace st = new StackTrace(true);
ConnectionSpy sl = new ConnectionSpy(con, st);
return con;
}

}
class Class1
{

[STAThread]
static void Main(string[] args)
{
//pipe trace output to the console
//in your app this would go to a trace file
Trace.Listeners.Add( new
TextWriterTraceListener(System.Console.Out));

String connect = "User Id=scott;Password=tiger;Data
Source=oracle";

OracleConnection con =
ConnectionFactory.OpenConnection(connect);
con = null; //!!the connection was not closed

con = ConnectionFactory.OpenConnection(connect);
con.Close(); //this time it was closed
con = null;

GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
//output will show 1 warning

}
}
}
 
this should absolutely not be happening. are you sure your results are
accurate. a webservice is inherently stateless which means nothing hangs
around. sure there may be a bit of optimization going on in the back end but
enough to cause a memory leak?

Have you eliminated that oracle provider as the cause? it is so buggy
 
Back
Top