CurlEasy causes a large memory leak.
http200it opened this issue · 7 comments
Hello again, faced a problem on Linux Mono 3.0 CurlEasy causes a large memory leak.
My test code:
public static void DoTestCurlEasy()
{
bool wykonuj = true;
int nrpetli = 0;
while (wykonuj)
{
using (var easy = new CurlEasy())
{
easy.Url = "http://www.xxxxxxx.com/dotest.html";
easy.WriteData = null;
easy.WriteFunction = OnWriteData;
easy.Perform();
}
Console.WriteLine("nrpetli: {0}", nrpetli);
nrpetli++;
Thread.Sleep(200);
}
}
public static Int32 OnWriteData(Byte[] buf, Int32 size, Int32 nmemb, Object extraData)
{
//var userData = (string)extraData;
//Console.Write(Encoding.UTF8.GetString(buf));
return size * nmemb;
}
Linux htop
Running is 0.9 MEM%
- 10 minutes
1.1 MEM%
1.2 MEM%
...
2.0 MEM%
And all the time the leak is getting bigger and RAM occupancy increases :(
Please check at the time, it may also fail to fix this :)
Thank you
It seems that the problem lies in the linux Momo though I have the latest version:
mono -V
Mono JIT compiler version 3.10.0 (tarball Mon Oct 13 14:05:11 EDT 2014)
Application
if ((nrpetli % 10) == 0)
{
GC.Collect();
Console.WriteLine("GC.Collect");
}
does not help
@http200it Indeed, it seems to be a Mono-specific problem. I tweaked your sample code to make it multi-threaded:
private static void Main(string[] args)
{
for (var i = 0; i < 8; i++)
{
var th = new Thread(DoTestCurlEasy);
th.Start();
}
Curl.GlobalCleanup();
}
public static void DoTestCurlEasy()
{
Curl.GlobalInit(CurlInitFlag.All);
var wykonuj = true;
var nrpetli = 0;
while (wykonuj)
{
using (var easy = new CurlEasy())
{
easy.Url = "http://localhost:88/data.txt";
easy.WriteData = null;
easy.WriteFunction = OnWriteData;
easy.Perform();
}
Console.WriteLine("nrpetli: {0}", nrpetli);
nrpetli++;
//Thread.Sleep(200);
}
}
public static Int32 OnWriteData(Byte[] buf, Int32 size, Int32 nmemb, Object extraData)
{
return size*nmemb;
}
The target URL
is a 10+ MB data file, so any memory leaks should crop up fairly easily. Even with the above muti-threaded example I was unable to detect memory leaks in .net.
Here's a screenshot after several minutes:
Memory usage is still not increased, it's hovering around 8.5 - 9 MB after running for several minutes.
Environment for the above screenshot is: Windows 8.1 x64 + .net 4.5.2 x64 + libcurl-64.
That's right, after many tests, I noticed that the problem regards the Linux platform Mono on Windows is not. Sorry for the inconvenience.
@http200it: Can you kindly experiment with the functions CurlEasy._curlWriteCallback()
, CurlEasy._curlReadCallback()
and see if explicitly releasing the memory buffer after invoking the callback delegates (_pfCurlWrite
& _pfCurlRead
respectively) will prevent the memory leaks?
Unfortunately I don't have access to a Linux/OS X box right now.
https://github.com/masroore/CurlSharp/blob/master/CurlSharp/CurlEasy.cs#L2090
later, see :)
@http200it I have tested the sample project under OS X (Yosemite) and Mono 3.10 and confirm the memory leak. I modified the source code to create 20 concurrent threads. On startup, memory usage hovered between 10-20 MB. After running the app for 3+ hours, I found the memory usage has crept up to ~140MB.
@masroore Thank you for confirming tests :)
I tested an application written in C ++ uses libcurl - Linux debian 7 64 Bit:
#curl -V
curl 7.38.0 (x86_64-unknown-linux-gnu) libcurl/7.38.0 NSS/3.14.5.0 zlib/1.2.7 c-ares/1.10.0 libidn/1.25 libssh2/1.4.2 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile NTLM NTLM_WB SSL libz
I say a big memory leak for HTTP (S) HTTP leak is not. Application pseudo code:
whiel(true)
{
curl_global_init(CURL_GLOBAL_ALL);
// app code
curl_global_cleanup();
}
reduces memory leak for HTTPS, but not suitable for threads.
In MONO 3.10 is also a leak for HttpWebRequest.
My test code seems to be correct are:
public static void OdpalaWatekTestowyDoHttps()
{
ServicePointManager.ServerCertificateValidationCallback = delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{ return true; };
for (int jjj = 0; jjj < 10; jjj++)
{
Thread MyThreadGZd = new Thread(() => DoTestWebRequestGet(jjj));
MyThreadGZd.Start();
}
}
public static void DoTestWebRequestGet(int nrwataka)
{
bool wykonuj = true;
int nrpetli = 0;
while (wykonuj)
{
HttpWebResponse response = null;
StreamReader reader = null;
HttpWebRequest request = null;
request = (HttpWebRequest) WebRequest.Create("https://www.domain.com/gfx/wyswietldate.php?randettsos=" + nrpetli.ToString());
request.Credentials = CredentialCache.DefaultCredentials;
request.ServicePoint.Expect100Continue = false;
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
request.KeepAlive = false;
request.UserAgent = "Mozilla/5.0 (Windows NT 5.1; rv:22.0) Gecko/20100101 Firefox/22.0";
try
{
response = (HttpWebResponse) request.GetResponse();
Stream dataStream = response.GetResponseStream();
reader = new StreamReader(dataStream);
string html = reader.ReadToEnd().Trim();
lock (lockThisOb)
{
Console.WriteLine("Status:{0} html: {1} nrpetli: {2} nrwataka: {3} ilewywolal: {4}", ((HttpWebResponse)response).StatusDescription, html, nrpetli, nrwataka, ClassPomocnicze.ilewywolal);
ClassPomocnicze.ilewywolal++;
}
}
catch(Exception exe)
{
Console.WriteLine("Exception {0} ", exe.Message);
}
finally
{
if (response != null)
{
response.Close();
response.Dispose();
response = null;
}
if (reader != null)
{
reader.Close();
reader.Dispose();
reader = null;
}
if (request != null)
{
request = null;
}
}
nrpetli++;
Thread.Sleep(1000);
}
}
/// end
However, the leakage is much smaller but increasing RAM busy hours
Leakage is not a similar test in JAVA applications.
Regards