Windows 大型稀疏数组创建指南:高效利用内存
2024-11-06 00:54:07
Windows 大型稀疏数组的创建
开发者经常需要创建大型数组来存储数据。但在处理稀疏数据(大部分元素为零)时,分配完整的内存空间显得非常浪费。 在 Linux 中,mmap
可以轻松创建巨大的稀疏数组,只在写入时分配物理内存。如何在 Windows 上实现类似的功能呢?这是一个许多开发者都会遇到的问题。
VirtualAlloc
的误区
许多开发者第一时间想到的可能是 VirtualAlloc
。 你可能尝试过保留一大块虚拟地址空间,而没有实际提交物理内存。 但是,直接读取未提交的内存会导致访问冲突,而不是返回零。这是因为未提交的内存页没有关联的物理存储。 如果你提交了内存,则会在读取时分配物理存储,失去了稀疏数组的优势。
CreateFileMapping
的限制
另一个常见的选择是 CreateFileMapping
和 MapViewOfFile
。这个方法通过创建一个内存映射文件来模拟稀疏数组。 但正如你所发现的,这个方法会占用大量的临时磁盘空间,并且数组大小受限于可用磁盘空间,难以创建真正的大型稀疏数组。
稀疏文件的解决方案:更优的选择
其实,Windows 提供了一个更优雅的解决方案:稀疏文件 (Sparse Files) 。 稀疏文件允许你创建一个很大的文件,但实际占用的磁盘空间只与文件中非零数据的大小相关。结合内存映射视图,就可以在 Windows 上高效地实现大型稀疏数组。 你只需要在创建文件时设置 FILE_FLAG_SPARSE_FILE
标志,然后像往常一样使用 CreateFileMapping
和 MapViewOfFile
即可。
下面是使用稀疏文件创建大型稀疏数组的代码示例:
#include <windows.h>
#include <iostream>
const size_t MB = 1024 * 1024;
const size_t GB = MB * 1024;
int main() {
size_t alloc_size = 512 * MB;
size_t total_alloc = 100 * GB;
HANDLE hFile = CreateFile(L"sparse_array.dat", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SPARSE_FILE , NULL);
if (hFile == INVALID_HANDLE_VALUE) {
std::cerr << "CreateFile failed: " << GetLastError() << std::endl;
return 1;
}
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, static_cast<DWORD>(total_alloc), NULL);
if (hMapping == NULL) {
std::cerr << "CreateFileMapping failed: " << GetLastError() << std::endl;
CloseHandle(hFile);
return 1;
}
char* base = (char*)MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, total_alloc);
if (base == NULL) {
std::cerr << "MapViewOfFile failed: " << GetLastError() << std::endl;
CloseHandle(hMapping);
CloseHandle(hFile);
return 1;
}
std::cout << "Allocated Virtual Mem (GB): " << total_alloc / GB << "\n";
std::cout << "Base Addr: " << (void*)base << "\n";
// 使用稀疏数组 (例如写入一些数据)
for (size_t i = 0; i < total_alloc; i += (1 * GB)) { // 每 GB 写入一次
base[i] = 1; // 只修改少量数据,保持稀疏性
}
UnmapViewOfFile(base);
CloseHandle(hMapping);
CloseHandle(hFile);
std::cout << "Done!" << std::endl;
return 0;
}
操作步骤:
- 使用
CreateFile
创建文件,并使用FILE_FLAG_SPARSE_FILE
标志。 - 使用
CreateFileMapping
创建文件映射对象。 - 使用
MapViewOfFile
将文件映射到内存。 - 现在你可以像使用普通数组一样使用
base
指针访问稀疏数组了。 - 完成后,使用
UnmapViewOfFile
、CloseHandle
关闭句柄释放资源。
安全建议
使用稀疏文件时,需要注意以下几点:
- 及时关闭文件和映射对象的句柄,释放系统资源。
- 谨慎处理访问权限,防止数据泄露或被篡改。
- 确保有足够的磁盘空间来存储非零数据。
其他的解决方案和建议?
除了稀疏文件,你还可以考虑使用其他方法来管理大型稀疏数据,例如使用专门的稀疏矩阵库或者数据库。每个方案都有其优缺点,选择合适的方案取决于你的具体需求。你还有其他更好的建议吗?不妨在评论区分享你的经验!
相关资源
- Microsoft Docs: Sparse Files
- Microsoft Docs: CreateFile
- Microsoft Docs: CreateFileMapping
- Microsoft Docs: MapViewOfFile
这个方法对你有帮助吗?希望这篇文章能帮助你更好地理解如何在 Windows 上创建和使用大型稀疏数组!