首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >WINAPI CreateFileMapping失败,错误为8- ERROR_NOT_ENOUGH_MEMORY

WINAPI CreateFileMapping失败,错误为8- ERROR_NOT_ENOUGH_MEMORY
EN

Stack Overflow用户
提问于 2017-09-02 11:54:39
回答 1查看 1.5K关注 0票数 4

我正在Windows上处理文件映射,但遇到了一些问题。首先,我有必要部分映射一个文件,并动态地设置它的开始和结束。

我的代码如下:

代码语言:javascript
运行
复制
long fiveMB = 5 * pow(2, 20);
for(int i=0;i<parts;i++){
    long start = (i)*fiveMB;
    long end = (i + 1)*fiveMB;
    long realEnd = end;
    if (roundedDim<realEnd)
        realEnd = dim;

    long chunkDim = realEnd - start;
    LARGE_INTEGER fileMapStart.QuadPart = (start/granularity)*granularity;
    LARGE_INTEGER mapViewSize.QuadPart = (start%granularity) + chunkDim;
    LARGE_INTEGER fileMapSize.QuadPart = start + chunkDim;
    long offset = start - fileMapStart.QuadPart;

    HANDLE fileMappingH= CreateFileMapping(fileH, NULL, PAGE_READONLY, fileMapSize.HighPart, fileMapSize.LowPart, NULL);

    if(fileMappingH == INVALID_HANDLE_VALUE || fileMappingH == NULL){
       printf("Error mapping file: %d\n",GetLastError());
       CloseHandle(fileH);
       return 1;
    }

    char *mapView = (char *)MapViewOfFile(fileMappingH, FILE_MAP_READ, fileMapStart.HighPart, fileMapStart.LowPart, mapViewSize.QuadPart);
    if ((LPVOID)mapView == NULL) {
        printf("Error mapView: %d\n", GetLastError());
        CloseHandle(fileMappingH);
        CloseHandle(file);
        return 1;
    }

    mapView += offset;

    /* doing all the stuff */

    UnmapViewOfFile((LPVOID)mapView);
    CloseHandle(fileMappingH);
}

据我所知,只有MapViewOfFile才要求开始字节与系统粒度对齐,因此我不需要为此修复最大的文件映射大小。

我在一个1448 KB文件(打印出1482159字节)上尝试了这段代码,同时通过GlobalMemoryStatusEx(&memstatus)和2092208128字节计算可用内存,但仍然坚持CreateFileMapping调用失败,错误代码8,ERROR_NOT_ENOUGH_MEMORY

我还尝试调用CreateFileMapping(fileH、NULL、PAGE_READONLY、0、0、NULL)来映射整个文件,但是在ERROR_ACCESS_DENIED错误5上却出现了问题。

我不明白我在这里做错了什么,因为我在同一个项目的Linux版本上成功地完成了mmap。

谢谢任何可能帮忙的人。

编辑:

  • C是个剩菜,我的意思是
  • 添加了UnmapViewOfFile和CloseHandle调用
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-09-02 14:10:55

据我所知,MapViewOfFile只要求起始字节与系统粒度()对齐,因此我不需要为它修复最大的文件映射大小。

这是错误的根源--真的来自MapViewOfFile

dwNumberOfBytesToMap in 要映射到视图的文件映射的字节数。所有字节必须在CreateFileMapping指定的最大大小之内。如果此参数为0(零),则映射将从指定的偏移量扩展到文件映射的末尾。

如果在MaximumSize中使用0作为CreateFileMapping,则文件映射对象的最大大小等于文件的当前大小。以及:

如果应用程序为文件映射对象指定的大小大于磁盘上实际命名文件的大小,如果页保护允许写访问PAGE_READWRITE,则指定(即flProtect参数指定或PAGE_EXECUTE_READWRITE),),则磁盘上的文件将增加以与文件映射对象的指定大小匹配。

还有关于GetLastError和win32的错误。在大多数情况下,错误以NTSTATUS代码的形式从内核返回。win32层通过NTSTATUS将指定的NTSTATUS代码转换为等效的系统错误代码。不幸的是,这个转换不是内射--许多不同的NTSTATUS代码可以转换成相同的win32错误,我们在这里丢失了敏感信息。

因此,在某些情况下,更好的调用RtlGetLastNtStatus()而不是GetlastError() --这提供了更多关于错误的信息。

CreateFileMapping调用失败,错误代码为ERROR_NOT_ENOUGH_MEMORY

基于误差ERROR_NOT_ENOUGH_MEMORY,我们可以认为系统内存不足(STATUS_NO_MEMORY)。但也有另一种状态-- STATUS_SECTION_TOO_BIG转换为ERROR_NOT_ENOUGH_MEMORYCreateFileMappingZwCreateSection上的瘦外壳,STATUS_SECTION_TOO_BIG在以下情况下返回:

MaximumSize的值太大了。如果MaximumSize大于系统定义的区段的最大值,或者MaximumSize 大于指定的文件,且区段不是可写的,则会发生这种情况。

这正是您的情况:您在调用PAGE_READONLY时使用了CreateFileMapping -所以部分是不可写的,fileMapSize大于指定的文件(文件映射对象的大小大于磁盘上实际文件的大小)。

MapViewOfFile返回ERROR_ACCESS_DENIED

再一次,GetLastError()和我们一起玩了一个残酷的笑话。最初的状态不是STATUS_ACCESS_DENIED如何等待,而是STATUS_INVALID_VIEW_SIZE。此状态也转换为ERROR_ACCESS_DENIED。当不是在MapViewOfFile指定的最大大小内的所有字节时,CreateFileMapping就会得到它。

并且在循环中多次调用CreateFileMapping -这是设计错误-只需要调用这个api一次,在循环之前。循环中只存在感知调用MapViewOfFile。测试代码可以是:

代码语言:javascript
运行
复制
void TestMap(PCWSTR lpFileName, ULONG dwChunkSize)
{
    HANDLE hFile = CreateFileW(lpFileName, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        FILE_STANDARD_INFO fsi;
        if (GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(fsi)))
        {
            if (HANDLE hSection = CreateFileMappingW(hFile, 0, PAGE_READONLY, 0, 0, 0))
            {
                if (ULONG n = (ULONG)((fsi.EndOfFile.QuadPart + (dwChunkSize - 1)) / dwChunkSize))
                {
                    LARGE_INTEGER ofs = {};
                    do 
                    {
                        if (PVOID pv = MapViewOfFile(hSection, FILE_MAP_READ, ofs.HighPart, ofs.LowPart, --n ? dwChunkSize : 0))
                        {
                            UnmapViewOfFile(pv);
                        }
                        else
                        {
                            RtlGetLastNtStatus();
                        }
                    } while (ofs.QuadPart += dwChunkSize, n);
                }

                CloseHandle(hSection);
            }
            else
            {
                RtlGetLastNtStatus();
            }
        }
        CloseHandle(hFile);
    }
    else
    {
        RtlGetLastNtStatus();
    }
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46013496

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档