2

对于这个问题,我将一个大的三维体积从文件加载到程序中,但通常一次只需要查看三个平面 (x,y,z)。我目前正在使用 Boost::Interprocess::File_Mapping 来创建文件的映射(32 GB)并将其加载到具有 24 GB RAM 的系统上。当前方法对文件使用单个 Boost::Interprocess::Mapped_Region。内存使用率迅速接近 99%。

我是内存映射文件 i/o 领域的新手,想知道如何最好地对文件进行分段以减少内存使用量。创建缩小尺寸的区域(例如每个 Z 平面)会改善结果吗?我想使用尽可能少的内存而不会造成不利影响。

我是否以正确的方式进行此操作,还是有更直接的方法来执行此操作?

4

1 回答 1

1

在 Windows 上,它通常可以正常工作。我创建了一个测试应用程序(对不起,我讨厌 boost,因为我认为它的质量令人震惊,我的示例使用 ATL,但底层 Windows API 是相同的):

HRESULT TestMain( LPCTSTR strFileName )
{
    CAtlFile file;
    HRESULT hr = file.Create( strFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING );
    if( FAILED( hr ) )
        return hr;
    CAtlFileMapping<BYTE> mapping;
    hr = mapping.MapFile( file );
    if( FAILED( hr ) )
        return hr;
    size_t sz = mapping.GetMappingSize();
    BYTE res = 0;
    for( size_t i = 0; i < sz; i++ )
        res ^= mapping[ i ];

    printf( "Read the complete file, %Iu bytes, the XOR is %.2X\n", sz, int( res ) );
    return S_OK;
}

当被要求在具有 8GB RAM 的机器上读取 12GB 文件时,我看到了您所描述的效果(我的进程的资源监视器内存数据:提交 25 MB,私有 20 MB,工作集和可共享 6.5 GB,这是我的数量空闲内存)。然而,互联网上的多个消息来源说这些数字没有任何意义并且不会影响性能,因为一旦任何进程请求更多内存,未使用的物理页面就会被丢弃,而且这个进程非常便宜(当然除非你正在写你的内存映射文件)。

或者,如果您对此行为真的不满意,您可以通过调用 VirtualUnlock 自己释放未使用的部分,如下所述:https ://stackoverflow.com/a/1882478/126995

或者,您只能映射您需要的文件部分。

但是您可以做的最好的事情是优化数据的布局。如果在您的数据文件中您将体素保留为double voxels[x][y][z],请将它们存储为struct { double voxels[8][8][8] } blocks[x/8][y/8][z/8]。这样,块大小正好是 4kb,也就是一个页​​面大小,如果你只需要访问例如 XZ 平面,你将节省大量的 I/O 带宽,数量级。只是不要搞砸错位,即如果您在数据之前有一个标题,请确保标题的大小是 4kb*n 其中 n 是整数。

于 2013-02-16T16:55:57.537 回答