Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB / C# Driver and Memory Issue

I'm using MongoDB 1.8.2 (Debian) and mongo-csharp-driver 1.1.0.4184 (IIS 7.5/.Net 4.0 x64).

Multiple items are inserted every second in a existing collection with ~ 3,000,000 objects (~ 1.9 GB).
The WebServer memory is increasing by ~ 1 MB after every insert -> which leads very fast to > 2 GB memory usage.
The memory is never released anymore and only an application pool recycle can free the memory.

Any ideas?

MongoServer server = MongoServer.Create(mongoDBConnectionString);
MongoDatabase database = server.GetDatabase(dbName);                

MongoCollection<Result> resultCollection = database.GetCollection<Result>("Result");
resultCollection.Insert(result);

result looks like

private class Result
{
    public ObjectId _id { get; set; }            
    public DateTime Timestamp { get; set; }
    public int Location { get; set; }            
    public string Content { get; set; }
}

UPDATE:

My problem is not the insert, it's the select - sorry weird codebase to investigate ;-)

I reproduced it with this sample Code:

Console.WriteLine("Start - " + GC.GetTotalMemory(false).ToString("#,###,##0") + " Bytes");

for (int i = 0; i < 10; i++)
{
    MongoServer server = MongoServer.Create(mongoDBConnectionString);
    MongoDatabase database = server.GetDatabase(dbName);

    MongoCollection<Result> resultCollection = database.GetCollection<Result>("Result");
    var query = Query.And ( Query.EQ("Location", 1), Query.GTE("Timestamp", DateTime.Now.AddDays(-90)) );

    MongoCursor<Result> cursor = resultCollection.FindAs<Result>(query);

    foreach (Result result in cursor)
    {
        // NOOP
    }

    Console.WriteLine(i + " - " + GC.GetTotalMemory(false).ToString("#,###,##0") + " Bytes");
}

Output from a .Net 4.0 Console Application with 10.000 results in the cursor:

Start - 193.060 Bytes
0 - 12.736.588 Bytes
1 - 24.331.600 Bytes
2 - 16.180.484 Bytes
3 - 13.223.036 Bytes
4 - 30.974.892 Bytes
5 - 13.335.236 Bytes
6 - 13.439.448 Bytes
7 - 13.942.436 Bytes
8 - 14.026.108 Bytes
9 - 14.113.352 Bytes

Output from a .Net 4.0 Web Application with the same 10.000 results in the cursor:

Start - 5.258.376 Bytes 
0 - 20.677.816 Bytes
1 - 29.893.880 Bytes
2 - 43.783.016 Bytes
3 - 20.921.280 Bytes
4 - 34.814.088 Bytes
5 - 48.698.704 Bytes
6 - 62.576.480 Bytes
7 - 76.453.728 Bytes
8 - 90.347.360 Bytes
9 - 104.232.800 Bytes

RESULT:

Bug was reported to 10gen and they will fix it in version >= 1.4 (they are working currently on 1.2)!!!

like image 831
mac866 Avatar asked Aug 02 '11 11:08

mac866


1 Answers

According to documentation you should create one instance of MongoServer for one server you connected to:

MongoServer class

This class serves as the root object for working with a MongoDB server. You will create one instance of this class for each server you connect to.

So you need only one instance of MongoServer. This should solve your memory leaks issue.

I suggest to use dependency injection (unity, structure map, ..) to register MongoServer instance in container as singletone or just use classic singletone pattern for MongoServer. If you new in dependency injection you can take a look in Martin Fowler article.

Update:

Probably issue was not in mongodb c# driver. I've made following testing:

w7, iis 7.5, same c# driver, same mongodb:

for (int i = 0; i < 3000000; i++)
{
   MongoServer server = MongoServer.Create("mongodb://localhost:27020");
   MongoDatabase database = server.GetDatabase("mpower_read");

   MongoCollection<Result> resultCollection = 
                              database.GetCollection<Result>("results");

   resultCollection.Insert(new Result()
   {
     _id = ObjectId.GenerateNewId(),
     Content = i.ToString(),
     Location = i,
     Timestamp = DateTime.Now
   });
}

I've even run this test 3 times and server not eat memory at all. So...

like image 76
Andrew Orsich Avatar answered Nov 12 '22 01:11

Andrew Orsich