JadeFileMapping::JadeFileMapping():m_dwSysGran(0),m_hFile(INVALID_HANDLE_VALUE),
   m_hMapping(NULL),m_lpDataBase(NULL)
{
SYSTEM_INFO SysInfo = { 0 };
GetSystemInfo(&SysInfo);
m_dwSysGran = SysInfo.dwAllocationGranularity;
}JadeFileMapping::~JadeFileMapping()
{
UnmapViewOfFile(m_lpDataBase);
if(m_hMapping != NULL)
{
CloseHandle(m_hMapping);
m_hMapping = NULL;
}
if(m_hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
}
m_dwSysGran = 0;
m_lpDataBase = NULL;
}DWORD JadeFileMapping::CreateFileMapping(LPCTSTR lpFile,DWORD dwRW,DWORD dwProtect,DWORD dwStart,DWORD dwEnd,
   DWORD dwBufSize,LPVOID *lpAddress)
{
DWORD dwFileMapStart = 0,dwMapViewSize = 0,dwFileMapSize = 0;
int iViewDelta = 0;
if(m_hMapping != NULL)
return JFMP_E_EXISTING;
if(m_hFile != INVALID_HANDLE_VALUE)
return JFMP_E_OPENNED;
m_hFile = CreateFile(lpFile,dwRW,FILE_SHARE_DELETE|FILE_SHARE_WRITE|FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(m_hFile == INVALID_HANDLE_VALUE)
return GetLastError();
//计算文件映射起始位置
dwFileMapStart = (dwStart/m_dwSysGran)*m_dwSysGran;
//文件映射大小
dwMapViewSize = (dwStart%m_dwSysGran)+dwBufSize;
//文件映射句柄大小
dwFileMapSize = dwStart + dwBufSize;
if( 0 > (iViewDelta = dwStart - dwFileMapStart) )
return JFMP_E_BADSTART;
//建立文件映射句柄
m_hMapping = ::CreateFileMapping(m_hFile,NULL,dwProtect,0,dwFileMapSize,NULL);
if(m_hMapping == NULL)
return GetLastError();
*lpAddress = MapViewOfFile(m_hMapping,FILE_MAP_ALL_ACCESS,0,dwFileMapStart,dwMapViewSize);
if(*lpAddress == NULL)
return GetLastError();
m_lpDataBase = *lpAddress;
*lpAddress = (char*)*lpAddress + iViewDelta;
return 0;
}DWORD JadeFileMapping::CreateFileMappingEx(LPCTSTR lpFile,DWORD dwRW,DWORD dwProtect,DWORD dwStart,
DWORD dwEnd,DWORD dwBufSize,LPVOID *lpAddress,
LPVOID lpBaseAddress)
{
DWORD dwFileMapStart = 0,dwMapViewSize = 0,dwFileMapSize = 0;
int iViewDelta = 0;
if(m_hMapping != NULL)
return JFMP_E_EXISTING;
if(m_hFile != INVALID_HANDLE_VALUE)
return JFMP_E_OPENNED;
m_hFile = CreateFile(lpFile,dwRW,FILE_SHARE_DELETE|FILE_SHARE_WRITE|FILE_SHARE_READ,
 NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(m_hFile == INVALID_HANDLE_VALUE)
return GetLastError();
//计算文件映射起始位置
dwFileMapStart = (dwStart/m_dwSysGran)*m_dwSysGran;
//文件映射大小
dwMapViewSize = (dwStart%m_dwSysGran)+dwBufSize;
//文件映射句柄大小
dwFileMapSize = dwStart + dwBufSize;
if( 0 > (iViewDelta = dwStart - dwFileMapStart) )
return JFMP_E_BADSTART;
//建立文件映射句柄
m_hMapping = ::CreateFileMapping(m_hFile,NULL,dwProtect,0,dwFileMapSize,NULL);
if(m_hMapping == NULL)
return GetLastError();
*lpAddress = MapViewOfFileEx(m_hMapping,FILE_MAP_ALL_ACCESS,0,dwFileMapStart,dwMapViewSize,
lpBaseAddress);
if(*lpAddress == NULL)
return GetLastError();
m_lpDataBase = *lpAddress;
*lpAddress = (char*)*lpAddress + iViewDelta;
return 0;
}异常处理部分自己加

解决方案 »

  1.   

    可以自己创建一个堆,重定义new操作符,在自己的堆中分配空间。
    也可以用事先预留地址空间的方法,在每次映射前释放空间,映射后再把剩余空间保留起来。非法操作应该是你的代码有问题。
      

  2.   

    地址空间碎片问题。
    可以自己做一层内存管理。用分块法实现。将整个进程的地址空间划分为若干区域,每个区域只存放固定大小的文件(文件大小不够则RoundUp为该区域分块大小)。
    例如,划分为A, B, C三个区域,分别存放大小为(0,1MB], (1MB,4MB], (4MB, 16MB]的文件。例如来了一个3MB的文件,就给他在B区预留并映射4MB的空间,来了个5MB的文件,就给他在C区预留并映射16MB的空间。
    该法可以去除外部碎片。但是会存在内部碎片,例如5MB的文件,将要浪费11MB的地址空间。
    另外该法也需要在最开始预测各区域的比例。如果进程允许有重启的机会,就好办了。可以利用重启的机会消除地址空间碎片,即重新加载到连续的区域。
    或者采用lazy策略,直到地址空间不够装下一个大文件时,才撤销所有映射,重新映射。此法类似.NET的内存垃圾回收策略。
      

  3.   

    我说的自己创建一个堆,目的是自己来管理内存,使避免造成内存碎片,是用来替代new而不是用来替代文件映射的。
    预留空间的方法,在每次Map和Unmap前后都要释放和分配内存,以保持地址空间连续,不被占用,只要确保中间过程没有其它线程分配内存,就不会有问题。不过这种做法不适合于同时交叠多个映射。