分配大于 32 位的堆内存允许
Allocating heap memory greater than 32-bit allows
我正在处理一个 32 位 OSGEarth 项目,我必须在其中将一系列图像拼接成一个大图像。切换到 64 位不是一个选项。
图像以 256x256 块的集合形式存储在内存中。
当用户试图从许多图块创建单个图像时,问题就出现了,OSGEarth 内部尝试分配比 32 位系统允许的更多的内存。
我试图通过分配几个数据块来绕过这个限制,每个数据块大小为 1025 字节。然后第 1025 个字节将 "point" 到下一个块的开头,最后一个字节是 nullptr。
这是我目前在做的事情(我打算以后分配更多):
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);
但是,如果我期望发生的事情真的发生了,我会有所保留。内存是否真正分配在一个连续的块中?如果不是,那么我的 memset 正在覆盖未分配的数据,这可能很糟糕。
有什么办法绕过 32 位限制吗?
Is the memory truly allocated in one, contiguous block?
无法保证。每次你调用 new 时,你都会得到一块位于内存中任何位置的内存。您实际上在做的是创建一个链表并且链表不连续。
如果您需要连续内存并且限制为 32 位,那么您真的无能为力。您可能能够捕获异常(如果出现异常)并向用户报告图像太大而无法创建。
在您的示例代码中,您没有检查 new
的结果以抛出 bad_alloc 异常。
当用户希望最终图像大于内存时会出现错误吗?将最终图像保存在内存中的要求是否固定?您使用什么算法将瓷砖拼接在一起?
我在使用 32MB RAM 的嵌入式系统时遇到了类似的问题。一个可能的解决方案可能是将最终图像作为文件保存在磁盘上,并在内存中只保留足够的信息来拼接下一个图块。这比在内存中分配一个巨大的块更耗时,但现在你受到磁盘大小的限制,而不是 32 位地址space(当然你会受到性能影响)。
对于 Windows,32 位可执行文件的可用内存默认限制为 2GB,即使 运行 在 64 位 Windows 下也是如此。要允许 32 位应用程序最多使用 4GB(尤其是 运行ning 在 64 位 Win 下),请设置 /LARGEADDRESSAWARE MSVC 链接器标志(背后的原因是 "unaware" 程序可能会处理 "negative" 地址错误,当然只有在编程错误的情况下,例如涉及 pointer/integer 转换)。
请注意,即使在现有的可执行文件中也可以更改此标志 - 它是 EXE header 中的掩码标志。可以使用 dumpbin 检查并使用 editbin 进行更改(均随 MSVC 提供),例如,请参见此处:http://gisgeek.blogspot.de/2012/01/set-32bit-executable-largeaddressaware.html
我正在处理一个 32 位 OSGEarth 项目,我必须在其中将一系列图像拼接成一个大图像。切换到 64 位不是一个选项。
图像以 256x256 块的集合形式存储在内存中。 当用户试图从许多图块创建单个图像时,问题就出现了,OSGEarth 内部尝试分配比 32 位系统允许的更多的内存。
我试图通过分配几个数据块来绕过这个限制,每个数据块大小为 1025 字节。然后第 1025 个字节将 "point" 到下一个块的开头,最后一个字节是 nullptr。
这是我目前在做的事情(我打算以后分配更多):
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);
但是,如果我期望发生的事情真的发生了,我会有所保留。内存是否真正分配在一个连续的块中?如果不是,那么我的 memset 正在覆盖未分配的数据,这可能很糟糕。
有什么办法绕过 32 位限制吗?
Is the memory truly allocated in one, contiguous block?
无法保证。每次你调用 new 时,你都会得到一块位于内存中任何位置的内存。您实际上在做的是创建一个链表并且链表不连续。
如果您需要连续内存并且限制为 32 位,那么您真的无能为力。您可能能够捕获异常(如果出现异常)并向用户报告图像太大而无法创建。
在您的示例代码中,您没有检查 new
的结果以抛出 bad_alloc 异常。
当用户希望最终图像大于内存时会出现错误吗?将最终图像保存在内存中的要求是否固定?您使用什么算法将瓷砖拼接在一起?
我在使用 32MB RAM 的嵌入式系统时遇到了类似的问题。一个可能的解决方案可能是将最终图像作为文件保存在磁盘上,并在内存中只保留足够的信息来拼接下一个图块。这比在内存中分配一个巨大的块更耗时,但现在你受到磁盘大小的限制,而不是 32 位地址space(当然你会受到性能影响)。
对于 Windows,32 位可执行文件的可用内存默认限制为 2GB,即使 运行 在 64 位 Windows 下也是如此。要允许 32 位应用程序最多使用 4GB(尤其是 运行ning 在 64 位 Win 下),请设置 /LARGEADDRESSAWARE MSVC 链接器标志(背后的原因是 "unaware" 程序可能会处理 "negative" 地址错误,当然只有在编程错误的情况下,例如涉及 pointer/integer 转换)。
请注意,即使在现有的可执行文件中也可以更改此标志 - 它是 EXE header 中的掩码标志。可以使用 dumpbin 检查并使用 editbin 进行更改(均随 MSVC 提供),例如,请参见此处:http://gisgeek.blogspot.de/2012/01/set-32bit-executable-largeaddressaware.html