【问题标题】:Using MapViewOfFile, pointer eventually walks out of memory space使用 MapViewOfFile,指针最终会走出内存空间
【发布时间】:2012-05-07 13:02:00
【问题描述】:

全部,

我正在使用 MapViewOfFile 将文件的一部分保存在内存中。有一个流指向这个文件并写入它,然后被倒带。我使用指向映射文件开头的指针,并读取直到我到达作为最后一个字符写入的空字符。

int fd;
yyout = tmpfile();
fd = fileno(yyout);
#ifdef WIN32
    HANDLE fm;
    HANDLE h = (HANDLE) _get_osfhandle (fd);

    fm = CreateFileMapping(
             h,
             NULL,
             PAGE_READWRITE|SEC_RESERVE,
             0,
             4096,
             NULL);
    if (fm == NULL) { 
            fprintf (stderr, "%s: Couldn't access memory space! %s\n", argv[0],  strerror (GetLastError()));
            exit(GetLastError());
    }
    bp = (char*)MapViewOfFile(
              fm,
              FILE_MAP_ALL_ACCESS,
              0,
              0,
              0);
    if (bp == NULL) { 
            fprintf (stderr, "%s: Couldn't fill memory space! %s\n", argv[0],  strerror (GetLastError()));
            exit(GetLastError());
    }

数据被发送到yyout 流,直到调用flushData()。这会将 null 写入流,刷新,然后倒回流。然后我从映射内存的开头开始,读取字符,直到我到达空值。

void flushData(void) {
    /* write out data in the stream and reset */ 
    fprintf(yyout, "%c%c%c", 13, 10, '\0');
    fflush(yyout);
    rewind(yyout);
    if (faqLine == 1) {
        faqLine = 0; /* don't print faq's to the data file */
    }
    else {
        char * ps = bp;
        while (*ps != '\0') {
                fprintf(outstream, "%c%c", *ps, blank);
                ps++;
            }
        fflush(outfile);
    }
    fflush(yyout);
    rewind(yyout);
}

刷新后,更多的数据被写入流,应该设置到内存区域的开头。就我可以用 gdb 确定的那样,流没有被倒带,并最终填满了分配的空间。

由于流指向底层文件,这最初不会导致问题。但是,当我尝试遍历内存时,我从来没有找到空值。这导致SIGSEV。如果你想了解我为什么需要这个的更多细节,see here

为什么我没有按预期重用内存空间?

【问题讨论】:

  • 你想达到什么目的?为什么代码没有同时取消映射视图并关闭句柄?
  • @STATUS_ACCESS_DENIED 这只是代码库的一个 sn-p,在我使用完映射空间后,我取消映射并关闭句柄。关键是将文件流重定向到 Windows 系统上的内存中。

标签: c windows pointers memory-leaks mmap


【解决方案1】:

完成地图后,只需取消地图即可。

UnmapViewOfFile(bp);

【讨论】:

    【解决方案2】:

    我认为 CreateFileMapping 的 MSDN 文档中的这一行可能是线索。

    映射文件和使用输入和输出 (I/O) 函数(ReadFile 和 WriteFile)访问的文件不一定是一致的。

    您显然没有使用 Read/WriteFile,但应该根据映射视图与显式 I/O 调用来理解文档。无论如何,C RTL 肯定是使用 Win32 API 实现的。

    简而言之,这种做法是有问题的。

    我不知道为什么更改视图/文件大小会有所帮助;也许它只是将未定义的行为转移到恰好有益的方向。

    【讨论】:

    • 我很担心。在这一点上,事情有效,我已经没有时间去追查了。直到它跳起来咬人,mngmt。要我继续前进。当然,除非有人提出解决方案……
    【解决方案3】:

    好吧,经过一段时间的研究,我有了一个可行的解决方案。我不知道为什么会成功,所以如果有人想出更好的东西,我很乐意接受他们的回答。

    fm = CreateFileMapping(
             h,
             NULL,
             PAGE_READWRITE|SEC_RESERVE,
             0,
             16384,
             NULL);
    

    如您所见,唯一的变化是将声明的大小从4096 改为16384。我不知道为什么当一次输入的总字符数不超过 1200 时这会起作用。如果有人能提供这方面的详细信息,我将不胜感激。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-17
      • 2015-08-08
      • 2012-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-26
      • 1970-01-01
      相关资源
      最近更新 更多