help me with memry leak! C#

Started by
28 comments, last by JohnnyCode 11 years, 11 months ago
As I have mentioned, the code does not leak unless those three lines are added, but you are right, here is the code:
the aplication starts two threads: this is body of thread one
[source]
void ListenToRequestsForward()
{
m_tcpListener.Start(40000);
if (!m_bIsBalancer)
{
m_tcpForwardListener.Start(40000);
m_tcpSecureListener.Start(40000);
}


while (m_bHttpServiceRunning)
{
LinkedListNode<CClient> nd = m_aClients.First;
try
{

while (m_tcpListener.Pending()) // accept new request
{
CClient cl = new CClient();
cl.m_pConnectionHandle = m_tcpListener.BeginAcceptTcpClient(null, null);


cl.m_iTimeOfConnection = System.Environment.TickCount;
cl.m_cTimeOfConnection = DateTime.Now.TimeOfDay;

cl.m_cTimeOfConnection = DateTime.Now.TimeOfDay;

{
m_aClients.AddLast(cl);
}

}
if (!m_bIsBalancer)
while (m_tcpSecureListener.Pending())
{
CClient cl = new CClient();
cl.m_bSecure = true;

cl.m_pConnectionHandle = m_tcpSecureListener.BeginAcceptTcpClient(null, null);

cl.m_cTimeOfConnection = DateTime.Now.TimeOfDay;



{
m_aClients.AddLast(cl);
}
}
if (!m_bIsBalancer)
while (m_tcpForwardListener.Pending()) // accept new request
{
CClient cl = new CClient();


cl.m_pConnectionHandle = m_tcpForwardListener.BeginAcceptTcpClient(null, null);

cl.m_cTimeOfConnection = DateTime.Now.TimeOfDay;


{
m_aClients.AddLast(cl);
}
}
}
catch (Exception e)
{

}
if (!m_bIsBalancer)
Thread.Sleep(10);

lock (m_aClients)
{
while (nd != null)
{
LinkedListNode<CClient> next = nd.Next;
CClient fclient = (CClient)nd.Value;
nd = next;

if (fclient.m_bIsFree)
m_aClients.Remove(fclient);
}
}
}
try
{
m_tcpForwardListener.Stop();
m_tcpListener.Stop();
m_tcpSecureListener.Stop();
}
catch{}

}
[/source]
this is a listen thread
Here is much more complicated manage thread
[source]
void ManageConnections()
{
// serve current requests
while (m_bHttpServiceRunning)
{

LinkedListNode<CClient> nd = m_aClients.First;
lock (m_aClients)
{
while (nd != null)
{
LinkedListNode<CClient> next = nd.Next;
CClient fclient = (CClient)nd.Value;
nd = next;
try
{
if (fclient.m_bSecure)
{
// process streaming as secure SSL
if (!fclient.m_bIsFree)
SSL_FinishConnectionAttempt(fclient);
if (!fclient.m_bIsFree)
SSL_ReadRequest(fclient);
if (!fclient.m_bIsFree)
SSL_ServeRequest(fclient);
if (!fclient.m_bIsFree)
SSL_ReturnRequest(fclient);
}
else
{
// process http protocol

if (!fclient.m_bIsFree)
F_FinishConnectionAttempt(fclient);
if (!fclient.m_bIsFree)
F_ReadRequest(fclient);
if (!fclient.m_bIsFree)
F_ServeRequest(fclient);

if (!fclient.m_bIsFree)
F_ReturnRequest(fclient);
}

}
catch (Exception e)
{
fclient.Release();
}
}
}

}

}
[/source]
From now on, only F_FinishConnectionAttempt() and F_ReadRequest() functions are run, beacouse in read function I perform only these 3 lines and release client,

this is F_FinishConnectionAttempt() function
[source]
void F_FinishConnectionAttempt(CClient fclient)
{
if (fclient.m_bConnected)
{
return;
}
else
{
if (fclient.m_pConnectionHandle.IsCompleted)
{
fclient.m_bConnected = true;
fclient.m_pClient = m_tcpListener.EndAcceptTcpClient(fclient.m_pConnectionHandle);
IPEndPoint ep = (IPEndPoint)fclient.m_pClient.Client.RemoteEndPoint;
fclient.m_sPublicIP = ep.Address.ToString();
fclient.port = ep.Port;
// check for amount of ips of the client being served

int amount = CheckClientForAmountOfIPsInTheStack(fclient);
if (amount >= m_iMaxOfConnectionsForanIP)
{
fclient.Release();
//m_aClients.Remove(fclient);
return;
}
fclient.m_pStream = fclient.m_pClient.GetStream();

}
}
}
[/source]
And now F_ReadRequest()
[source]
void F_ReadRequest(CClient client)
{
if (DateTime.Now.TimeOfDay - client.m_cTimeOfConnection > m_cMaxConnectionDuration)
{
{
client.Release();
return;
}

}
if (!client.m_bConnected)
return;




if (client.m_bRecieveComplete == true)
return;

// start to read request
if (client.m_pRHandle == null) // have not started receiving bytes
{
//client.Release(); return; // if I uncomment this line no leak is performed

byte[] buff = new byte[4000];
client.m_pRHandle = client.m_pStream.BeginRead(buff, 0, 4000, null, null);
int redbytes = client.m_pStream.EndRead(client.m_pRHandle);

client.Release(); return;


}
else
{
//................ this never runs

[/source]
Advertisement
Ugh, what a mess...

At the very least you're not disposing of TcpClients when accepting new ones. And there's a pile of streams not being disposed of properly even if Release does what it is supposed to. Can you do a plain old blocking read rather than BeginRead? I suspect the callback is required, but haven't ever used the asynchronous stuff.

Ugh, what a mess...

At the very least you're not disposing of TcpClients when accepting new ones.


F_FinishConnectionAttempt() assigns TcpClient exactly once, as this whole routine must be performed exactly once for program to be functional.

And there's a pile of streams not being disposed of properly even if Release does what it is supposed to. Can you do a plain old blocking read rather than BeginRead? I suspect the callback is required, but haven't ever used the asynchronous stuff.
[/quote]
The Release function is not cousing the leak for sure, those other streams are not created in this leak studying scenario, msdn also says that NetworkStream.Close() calls Dispose() function. I am gonna try synchronous read about theese 3 lines as you suggested to investigate this further.

What I am starting to believe is that native objects allocated by NetworkStream class are not freed to OS somehow. Using delegates leaks too. I am not going that way but I have tried it. I am gona replace theese 3 lines with synchronous read like this:
[source]
byte[] buff = new byte[4000];
client.m_pStream.Read(buff, 0, 4000);
client.Release(); return;
[/source]
Once you start randomly assuming that core platform and OS components are broken, you've lost all chance you had at solving the problem rationally. At this point you might as well start banging on the keyboard and hoping that it all works out in the end.


Using delegates leaks too
[/quote]

I mean, really? Come on now. An integral feature of popular and widely used runtime leaks huge amounts of memory? What are the odds of that?
Mike Popoloski | Journal | SlimDX
so with synchronous read it is not leaking for sure. If instead I use
[source]
byte[] buff = new byte[40000];
client.m_pRHandle = client.m_pStream.BeginRead(buff, 0, 4000, null, null);
int redbytes = client.m_pStream.EndRead(client.m_pRHandle);

client.Release(); return;
[/source]
It leaks.

Really

Once you start randomly assuming that core platform and OS components are broken, you've lost all chance you had at solving the problem rationally. At this point you might as well start banging on the keyboard and hoping that it all works out in the end.


I admitt. I am really thinking for wraping c++ winsocks on my own to C#. About the delegates. I do not need to assign a static function that runs as a thread and extract my data there, I tried: 100 CPU load and slow, can handle few times less requests, I admit I was performance unsmart when doing it but still it should not happen to such extend.
please , help, any suggestion can save me.
I really didn't mean to be unpolite, I am sorry if I sounded so. Thank you all for help. I am not trolling guys, I am realy facing this problem I described. It is unbelievable even for me as I do not know what to inspect in the three lines that makes my project leak if I add them to it. I realy perform no other change.
Sorry, I am not that familiar with the async stuff. How is the synchronous read insufficient again?
synchronous read performs absolutely correctly.
I have studied something about socket communication and what I have found out is:- asynchronous calls are a derivation of synchronous calls (I have thought otherwise formely). Synchronous calls are much more native to hardware than asynchronous one. Asynchronous call in fact calls synchronous read in a separate thread- this loads no cpu time as synchronous read performs away hardware routine on the net device and returns the data.

So I saved myself from wraping socket c++ library by manualy creating thread that contains only synchronous read on a stream. It blocks, takes time, but do not use cpu at all. I am totaly happy with this. Here is the class that I migrated the whole project in a minute to:

[source]



public class CNetworkStream
{
private NetworkStream m_pStream = null;
public CNetworkStream(NetworkStream stream)
{
m_pStream=stream;
}
public CAsyncResult BeginRead(byte[] buff,int offset,int count,object n1,object n2)
{
CAsyncResult res = new CAsyncResult();
res.offset = offset;
res.buff = buff;
res.count = count;
res.m_pStream = m_pStream;
Thread readthread = new Thread(ReadInThread);
readthread.Start(res);
return res;
}
public int EndRead(CAsyncResult what)
{
while (!what.IsCompleted) ;

return what.redbytes;
}
private static void ReadInThread(object data)
{
CAsyncResult res = (CAsyncResult)data;
int red = 0;

try { red = res.m_pStream.Read(res.buff, res.offset, res.count); }
//catch (Exception e) { res.IsCompleted = true; throw e; }
catch{}
res.redbytes = red;
res.IsCompleted = true;
}


////////////write
public CAsyncResult BeginWrite(byte[] buff, int offset, int count,object n1,object n2)
{
CAsyncResult res = new CAsyncResult();
res.offset = offset;
res.buff = buff;
res.count = count;
res.m_pStream = m_pStream;
Thread readthread = new Thread(WriteInThread);
readthread.Start(res);
return res;
}
public void EndWrite(CAsyncResult what)
{
while (!what.IsCompleted) ;

}
private static void WriteInThread(object data)
{
CAsyncResult res = (CAsyncResult)data;

try { res.m_pStream.Write(res.buff, res.offset, res.count); }
//catch (Exception e) { res.IsCompleted = true; throw e; }
catch { }
res.IsCompleted = true;
}
public void Close()
{
m_pStream.Close();
}
}


public class CAsyncResult
{
public bool IsCompleted = false;
public int redbytes = 0;
public NetworkStream m_pStream;

public byte[] buff;
public int offset;
public int count;
};


[/source]

I know there are weak design parts, but it serves my purpose greatly.

This topic is closed to new replies.

Advertisement