2

I am working on a 32-bit OSGEarth project, where I have to mosaic a selection of images together into one large image. Switching to 64-bit is not an option.

Images are stored in-memory as a collection of 256x256 tiles. The problem arises when the user attempts to create a single image from many tiles, OSGEarth internally attempts to allocate more memory than a 32-bit system will allow.

I'm attempting to get around this limitation by allocating several chunks of data, each sized 1025 bytes. The 1025'th byte will then "point" to the beginning of the next chunk, with the last byte being a nullptr.

This is what I am currently doing (I plan to allocate much more in the future):

unsigned char* start = new unsigned char[1025];
unsigned char** head = &start;
unsigned char** tail = head + 1025;

for (unsigned int i = 0; i < 3; ++i)
{
    auto c = new unsigned char[1025];
    *tail = &c[0];
    tail = &c + 1025;
}

memset(head, 'C', 1025 * 4);

However, I have some reservations if what I am expecting to happen is actually happening. Is the memory truly allocated in one, contiguous block? If not, then my memset is writing over unallocated data, which could be bad.

Is there any way around the 32-bit limitations?

Acorn
  • 1,147
  • 12
  • 27
  • 4
    *Switching to 64-bit is not an option* -- You can't squeeze blood out of a stone. Maybe it's time to reconsider? – PaulMcKenzie Aug 01 '16 at 19:32
  • "The problem arises when […] OSGEarth […] attempts to allocate more memory than a 32-bit system will allow." You mean more than 3GiB? – ysdx Aug 01 '16 at 20:08
  • I'm working with high-resolution maps of the earth. The images themselves tend to be smaller, but the data OSG asks for is indeed up in the gigabytes. – Acorn Aug 01 '16 at 20:13
  • Which OS? If the problem is mainly under Windows, are you aware of the `/LARGEADDRESSAWARE` MSVC linker flag? - Windows only allows max. 2GB by default, for 32-bit app running on 64-bit system, with this flag it allows up to 4GB (Linux allows addresses >2GB by default). – EmDroid Aug 01 '16 at 20:16
  • I was not aware of that flag, I'll bring it up to the powers in charge. – Acorn Aug 01 '16 at 20:18

3 Answers3

5

Is the memory truly allocated in one, contiguous block?

There is no guarantee. Every time you call new you could be given a block of memory that is anywhere in memory. What you are effectively doing is creating a linked list and linked list are not contiguous.

If you need contiguous memory and are limited to 32 bits then there really isn't anything you can do. You might be able to catch the exception(if one is surfaced) and report to the user that the image is to large to be created.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • That is what I feared. Working with osg::Image, I see nothing that allows me to hand it chunks of data and tell it the data is not contiguous, either. Time for a meeting! – Acorn Aug 01 '16 at 19:31
1

For Windows, memory available to a 32-bit executable is limited to 2GB by default, even if run under 64-bit Windows. To allow use up to 4GB for 32-bit app (especially if running under 64-bit Win), set the /LARGEADDRESSAWARE MSVC linker flag (the reason behind is that the "unaware" program might handle "negative" addresses wrong, of course only if programmed badly, e.g. pointer/integer conversions involved).

Note that this flag can be changed even in an existing executable - it is a mask flag in the EXE header. Can be checked with dumpbin and changed with editbin (both come with MSVC), see for example here: http://gisgeek.blogspot.de/2012/01/set-32bit-executable-largeaddressaware.html

EmDroid
  • 5,918
  • 18
  • 18
0

In your sample code you don't check the result of new for throwing a bad_alloc exception.

Is the error occurs when the user wants the final image to be larger than memory? Is the requirement to keep the final image in memory fixed? What algorithm do you use to stitch the tiles together?

I had a similar problem while working on an embedded system with 32MB of RAM. A possible solution may be to keep the final image as a file on disk and keep in memory only enough information to stitch the next tile. It is more time consuming than just allocating one giant block in memory, but now you are limited by your disk size, not 32-bit address space (and you get a performance hit, of course).

ilya1725
  • 4,496
  • 7
  • 43
  • 68
  • 3
    `new` doesn't return `nullptr`. It throws an exception. – milleniumbug Aug 01 '16 at 20:09
  • I've thought about this, stitching the two images together. It could work, but then comes another problem. Later on, the image is scaled way up (we are working with high-res maps). I don't think it's possible to scale the image up as high as it wants to, with the limited amount of memory we have. – Acorn Aug 01 '16 at 20:17
  • Why can't you scale the image pieces also? Or scale the tiles first then stitch? Scaling is a linear operation. – ilya1725 Aug 01 '16 at 20:34
  • @milleniumbug: you are right. I've gotten my C and C++ mixed up. – ilya1725 Aug 01 '16 at 20:40
  • @ilya1725 that is true, I didn't think about scaling then stitching. I'll attempt doing that. – Acorn Aug 01 '16 at 20:48