Massoud Mazar

Sharing The Knowledge

NAVIGATION - SEARCH

Sql Server Spatial and Unmanaged Memory Leak

Encountering memory leaks in a .net application is not very common, but when dealing with one which is not common and you cannot find any mention of it online, it is even harder to resolve. I had one of these encounters this week and took me a couple of days to find a solution for it.

A product I'm working on, makes extensive use of SQL server DbGeometry types to store and manipulate GIS data. DbGeometry type is provided in the System.Data.Entity.Spatial library, which can be added to your .net code using the Microsoft.SqlServer.Types NuGet package. After a trivial change in the code I realized it is failing on the QA server where it was deployed to. Strangely there was no failure on the development machine. Failure on the server was surfacing as processing taking so ling it would timeout. Observing the server health revealed unprecedented memory use when this new part of code was being executed.

Same high memory use was not observed on my development machine, so I used ANTS Memory Profiler to see what is using the memory, and voila, Giga Bytes of unmanaged memory was being consumed by SqlServerSpatial110 library.

I was able to narrow down the problem to this piece of code:

var box = boxes.Where(b => b.AssetShape.Intersects(newShape)).First();
if (box != null)
{
    box.AssetShape = box.AssetShape.Union(newShape);
}

 

Which "Boxes" is a List<Box> and AssetShape is just a DbGeometry. You would expect that doing a Union on two DbGeometry variables and storing the result in one of them should work, but it proved to be the problem. Even sting the Union result in a temp variable and replacing the original value with the temp value did not make any difference.

I tried everything I could think of, but the only way I could work around this issue was to remove the box object from Boxes collection, recreate a new Box object and add it to the collection:

 

var box = boxes.Where(b => b.AssetShape.Intersects(newShape)).First();
if (box != null) { // An in-place update of the AssetShape caused Memory Leak, only the following approach worked boxes.Remove(box); boxes.Add(new Box { Id = box.Id, BoxShape = box.BoxShape, AssetShape = box.AssetShape.Union(newShape), }); }

I cannot explain why this is hapenning, so feel free to comment if you know the reason.

Add comment