C++ 分配大于32位的堆内存允许

C++ 分配大于32位的堆内存允许,c++,memory,memory-management,openscenegraph,C++,Memory,Memory Management,Openscenegraph,我正在做一个32位的OSGEarth项目,我必须把一系列的图像拼接成一个大图像。切换到64位不是一个选项 图像作为256x256块的集合存储在内存中。 当用户试图从多个磁贴创建单个图像时,问题就会出现,OSGEarth会在内部尝试分配比32位系统允许的内存更多的内存 我试图通过分配几个数据块来绕过这个限制,每个数据块大小为1025字节。然后,第1025个字节将“指向”下一个块的开头,最后一个字节是nullptr 这就是我目前正在做的(我计划在未来分配更多): unsigned char*star

我正在做一个32位的OSGEarth项目,我必须把一系列的图像拼接成一个大图像。切换到64位不是一个选项

图像作为256x256块的集合存储在内存中。 当用户试图从多个磁贴创建单个图像时,问题就会出现,OSGEarth会在内部尝试分配比32位系统允许的内存更多的内存

我试图通过分配几个数据块来绕过这个限制,每个数据块大小为1025字节。然后,第1025个字节将“指向”下一个块的开头,最后一个字节是nullptr

这就是我目前正在做的(我计划在未来分配更多):

unsigned char*start=新的unsigned char[1025];
未签名字符**head=&start;
无符号字符**tail=head+1025;
for(无符号整数i=0;i<3;++i)
{
自动c=新的无符号字符[1025];
*tail=&c[0];
尾部=&c+1025;
}
memset(头部'C',1025*4);
然而,如果我期望发生的事情真的发生了,我有一些保留意见。内存是否真正分配在一个连续的块中?如果没有,那么我的memset正在写入未分配的数据,这可能是不好的

有没有办法绕过32位限制

内存是否真正分配在一个连续的块中

没有保证。每次调用new时,您都会得到内存中任意位置的内存块。实际上,您所做的是创建一个链表,而链表是不连续的


如果您需要连续内存,并且限制为32位,那么您真的无能为力。您可能能够捕获异常(如果出现异常)并向用户报告要创建的图像太大。

在示例代码中,您不会检查
new
引发异常的结果

当用户希望最终图像大于内存时是否发生错误?在内存中保留最终图像的要求是固定的吗?你用什么算法把瓷砖缝合在一起


在使用32MB内存的嵌入式系统时,我遇到了类似的问题。一个可能的解决方案是将最终图像作为文件保存在磁盘上,并在内存中只保留足够的信息来缝合下一个磁贴。这比只在内存中分配一个巨大的块要耗费更多的时间,但现在您受到磁盘大小的限制,而不是32位地址空间的限制(当然,您会受到性能的影响)。

对于Windows,默认情况下,32位可执行文件的可用内存限制为2GB,即使在64位Windows下运行也是如此。要允许32位应用程序最多使用4GB(特别是在64位Win下运行时),请设置MSVC链接器标志(其原因是“不知道”程序可能会处理错误的“负”地址,当然,只有在编程错误的情况下,例如涉及指针/整数转换)


请注意,即使在现有的可执行文件中也可以更改此标志-它是EXE头中的掩码标志。可以用dumpbin检查,也可以用editbin更改(两者都随MSVC提供),请参见此处的示例:

这正是我所担心的。在使用osg::Image时,我看不到任何东西允许我将数据块交给它,并告诉它数据也不是连续的。该开会了!切换到64位不是一个选项——你不能从石头中挤出血液。也许是时候重新考虑了?”当[…]OSGEarth[…]试图分配超过32位系统允许的内存时,问题就出现了。“你的意思是超过3GiB?我正在处理高分辨率的地球地图。图像本身往往较小,但OSG要求的数据确实达到了千兆字节。哪个操作系统?如果问题主要出现在Windows下,您是否注意到
/largeaddressware
MSVC链接器标志Windows默认只允许最大2GB,对于64位系统上运行的32位应用程序,此标志允许最多4GB(Linux默认允许地址>2GB)。我不知道该标志,我将把它带到负责人手中。
new
不会返回
nullptr
。它抛出了一个异常。我考虑过这个问题,将两幅图像缝合在一起。它可能会起作用,但随后又出现了另一个问题。稍后,图像将按比例放大(我们正在使用高分辨率贴图)。我认为在我们有限的内存下,不可能将图像放大到它想要的高度。为什么不能将图像片段也放大?还是先缩放瓷砖,然后缝合?缩放是一种线性操作。@milleniumbug:你说得对。我已经把C和C++混合了。@ ILY171725是真的,我没有考虑缩放然后拼接。我会试试的。
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);