0

我正在编写一个使用文件映射注销到文件的程序。
当我想读取日志时,Logger::Destroy()会调用,以便将文件映射视图上写入的内容刷新到物理文件中。代码如下:

int Logger::Destroy() {
    if (m_lpMapAddress) {
        auto bRet = UnmapViewOfFile(m_lpMapAddress);
        // succeed
    }

    if (m_hMapFile) {
        auto bRet = CloseHandle(m_hMapFile);
        // succeed
        m_hMapFile = NULL;
    }

    int nSize = m_lpCurAddress - m_lpMapAddress;
    if (nSize > 0
        && nSize < (1024 * 1024 * 16 * 2))
    {
        DWORD dwPtr = SetFilePointer(m_hFile, nSize, 0, FILE_BEGIN);

        ///// Succeed
        // if (dwPtr == INVALID_SET_FILE_POINTER)
        //  DbgViewOut(__FUNCTION__ " SetFilePointer error: %d \n", GetLastError());

        //// Error occurs :  "SetEndOfFile returned : 0 1224"
        BOOL bRet = SetEndOfFile(m_hFile);
        DbgViewOut(__FUNCTION__ " SetEndOfFile returned : %d %d\n", bRet, GetLastError()); 
    
        ....
    }

    m_lpMapAddress = m_lpCurAddress = NULL;

    return 0;
}

问题SetEndOfFile()失败了ERROR_USER_MAPPED_FILE,甚至CloseHandle(m_hMapFile)成功了。所以我用谷歌搜索了微软关于文件映射的手册,并对其中的一些进行了评论。

https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle

即使有仍然打开的文件视图,关闭文件映射的句柄也可以成功。有关详细信息,请参阅关闭文件映射对象。

https://docs.microsoft.com/en-us/windows/win32/memory/closing-a-file-mapping-object

当每个进程完成使用文件映射对象并取消映射所有视图时,它必须通过调用 CloseHandle 关闭文件映射对象的句柄和磁盘上的文件。即使有仍然打开的文件视图,这些对 CloseHandle 的调用也会成功。但是,保留文件视图映射会导致内存泄漏。

它说我无法相信 的结果CloseHandle()
而且我找不到解决方案。

任何人都可以帮助我吗?谢谢。


补充:我打Logger::Destroy()进来了std::lock_guard<std::mutex>,这对麻烦有影响吗?

: 我已经测试过了,锁不影响它。


更新:我已阅读何时出现错误 1224:ERROR_USER_MAPPED_FILE?. 而且我认为没有太大的区别。我附加了Logger::Initialize()初始化文件映射的代码。
而且,Logger::Initialize()两者Logger::Destroy()都在同一个进程和线程中,无需与他人共享。

int Logger::Initialize()
{
  m_hFile = CreateFileA(
      m_zFileName.c_str()
      , GENERIC_READ | GENERIC_WRITE
      , FILE_SHARE_READ | FILE_SHARE_WRITE
      , NULL                          
      , CREATE_ALWAYS
      , FILE_ATTRIBUTE_NORMAL
      , NULL);

  if (m_hFile == INVALID_HANDLE_VALUE) {
      DbgViewOut(__FUNCTION__  " CreateFileA error: %d \n", GetLastError());
      return -1;
  }

  m_hMapFile = CreateFileMappingA(
      m_hFile
      , NULL
      , PAGE_READWRITE
      , 0
      , 1024 * 1024 * 16 * 2
      , m_zMapKey.c_str());

  if (!m_hMapFile) {
      DbgViewOut(__FUNCTION__  " CreateFileMapping error: %d \n", GetLastError());
      return -1;
  }

  m_hMapFile = OpenFileMappingA(FILE_MAP_WRITE, TRUE, m_zMapKey.c_str());
  if (m_hMapFile == NULL) {
      DbgViewOut(__FUNCTION__ " OpenFileMapping error: %d \n", GetLastError());
      return -1;
  }

  m_lpMapAddress = (BYTE*)MapViewOfFile(
      m_hMapFile              // handle to mapping object
      , FILE_MAP_ALL_ACCESS   // read/write
      , 0                 // high-order 32 bits of file offset
      , 0                 // low-order 32 bits of file offset
      , 0);                // number of bytes
  if (m_lpMapAddress == NULL) {
      DbgViewOut(__FUNCTION__ " MapViewOfFile error: %d \n", GetLastError());
      return -1;
  }

  m_lpCurAddress = m_lpMapAddress;

  return 0;
}
4

1 回答 1

0

我会回答我自己的问题。

问题是我调用OpenFileMappingA()after CreateFileMappingA(),所以m_hMapFile返回的 byCreateFileMappingA()正在泄漏。我已经删除OpenFileMappingA(),问题消失了。

我曾经知道它必须在创建句柄后打开一次,几个月前我曾经在进程之间的内存共享中这样做。但是在这次争论中,我意识到创建后没有必要打开句柄。

非常感谢@RemyLebeau 的详细建议。

int Logger::Initialize()
{
    m_hFile = CreateFileA(
        m_zFileName.c_str()
        , GENERIC_READ | GENERIC_WRITE
        , FILE_SHARE_READ | FILE_SHARE_WRITE
        , NULL                          
        , CREATE_ALWAYS
        , FILE_ATTRIBUTE_NORMAL
        , NULL);

    if (m_hFile == INVALID_HANDLE_VALUE) {
        DbgViewOut(__FUNCTION__  " CreateFileA error: %d \n", GetLastError());
        return -1;
    }


    m_hMapFile = CreateFileMappingA(
        m_hFile
        , NULL
        , PAGE_READWRITE
        , 0
        , LINM_LOGGER_FILE_MAXSIZE * 2
        , m_zMapKey.c_str());

    if (!m_hMapFile) {
        DbgViewOut(__FUNCTION__  " CreateFileMapping error: %d \n", GetLastError());
        return -1;
    }

//// This was the solution - CreateFileMappingA & OpenFileMappingA mustn't be used for same process or thread.
//
//  m_hMapFile = OpenFileMappingA(FILE_MAP_WRITE, TRUE, m_zMapKey.c_str());
//  if (m_hMapFile == NULL) {
//      DbgViewOut(__FUNCTION__ " OpenFileMapping error: %d \n", GetLastError());
//      return -1;
//  }

    m_lpMapAddress = (BYTE*)MapViewOfFile(
        m_hMapFile              // handle to mapping object
        , FILE_MAP_ALL_ACCESS   // read/write
        , 0                 // high-order 32 bits of file offset
        , 0                 // low-order 32 bits of file offset
        , 0);                // number of bytes
    if (m_lpMapAddress == NULL) {
        DbgViewOut(__FUNCTION__ " MapViewOfFile error: %d \n", GetLastError());
        return -1;
    }

    m_lpCurAddress = m_lpMapAddress;

    return 0;
}
于 2021-07-25T04:12:25.973 回答