This project has moved and is read-only. For the latest updates, please go here.

GdalRasterLayer memory leak

Topics: Algorithms, Italiano, SharpMap Project
Mar 15, 2013 at 1:11 PM
Edited Mar 15, 2013 at 1:12 PM
I noticed this code in
protected virtual void GetPreview(Dataset dataset, Size size, Graphics g, BoundingBox displayBbox, ICoordinateSystem mapProjection, Map map)

// create 3 dimensional buffer [band][x pixel][y pixel]
                    double[][] tempBuffer = new double[Bands][];
                    double[][][] buffer = new double[Bands][][];
this causes a huge memory use in the application

This is what I suggest:
1) buffers should be byte instead of double
double[][] tempBuffer = new double[Bands][];
// get data from image
for (int i = 0; i < Bands; i++)
tempBuffer[i] = new double[displayImageLength * displayImageHeight];
should be

// get data from image
for (int i = 0; i < Bands; i++)
byte[] tempBuffer = new byte[displayImageLength * displayImageHeight];

by the way I think this code lacks some memory clean

Am I wrong?
Mar 15, 2013 at 2:41 PM
You are right that the memory usage is not very efficient. But rasters are not always images that you can break down to byte (a, r,g,b) values. That is why we use double at this place.
Mar 15, 2013 at 4:04 PM
Edited Mar 15, 2013 at 4:05 PM
My map has 18 raster layers (18 .ecw files) and some other vector layers
Sometimes I have to print the map into A0 format. That implicates that my Bitmap has to be ~3.000x4.000 pixels.
So in this case the variable tempbuffer reaches ~12.000.000x3 = ~36.000.000 doubles = ~36.000.000x8 bytes = 288.000.000 bytes = ~274MB
and the variable buffer takes another 274MB
Add the print buffer, add the Bitmap size in memory, add some dirty memory... 2 GB are reached and the program crashes

I tried to split the Bitmap into smaller bitmaps, but the result is the same. The biggest image I can print is in A2 format, that means I have to print 8 A2 images to build my A0 sheet, and I can wait an hour for getting the result
(8 Map.ZoomToBox() method and 8 drawing cycles)
Mar 15, 2013 at 5:51 PM
Edited Mar 15, 2013 at 5:52 PM
btw, if I'm getting right

analyzing the function GetPreview:
  • The variable buffer contains double values.
  • These values are used to fill another double array: intVal
  • in some cases intVal gets color.B, color.G, color.R that are bytes.
  • in other cases intVal gets ColorEntry.c1, ColorEntry.c2, ColorEntry.c3 that are short ints
  • in case of color correct I think intVal is corrected with an alpha coefficient or some other things
  • by the way, intVal ends in WritePixel function as double
  • in the WritePixel function intVal ends in a variable called row, and it's a byte* variable!
I see many (byte)intVal[<index>] conversion in WritePixel () function

so why does intVal has to be double?
Mar 16, 2013 at 10:54 AM
The easiest way to solve your problem is to work through the raster in slices. I'll take a look at it.
You are right that eventually the GdalRasterLayer is creating an image and thus boils the double down to a byte value, but the logic inside GdalRasterLayer tries to cope with all raster sources there are, not just images.
Mar 18, 2013 at 9:42 AM
Yes, I got your point, but in view of a possible memory enhancement, it could be useful considering to allocate less contiguous memory; for example tempBuffer has no meaning to live outside the below cycle... A little improvement can be to declare it inside the cycle and if possibile, to use the GC (as long as it's not a speed problem)

What do you think?
Mar 18, 2013 at 12:25 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.