工作中遇到一個問題,我們的程序內存占用太大,在目標機器上跑着跑着就崩潰了。經過高手提點,可以把某些內存映射到文件中,從而可以省下一些內存。現在做個記錄方便以后查閱。
在linux上, 用mmap這個方法:
1 int dumpFileDescriptor = open(mmFileName, O_CREAT | O_RDWR, 0755); 2 3 if(dumpFileDescriptor != -1) 4 { 5 void* mappedFileAddress = mmap(NULL, 6 MMAP_ALLOCATOR_SIZE, 7 PROT_READ | PROT_WRITE, 8 MAP_SHARED, 9 dumpFileDescriptor, 10 0); 11 } 12 13 // Do something use mappedFileAddress
函數msysc可以保證把數據同步到了磁盤上
1 msync(mappedFileAddress, MMAP_ALLOCATOR_SIZE, MS_SYNC);
等不用的時候,用unmap函數解除映射
1 munmap(mappedFileAddress, MMAP_ALLOCATOR_SIZE);
然后可以用unlink把映射文件刪掉,如果需要的話
1 unlink(mmFileName);
同時我在網上搜了一下,windows下面用CreateFileMapping
1 HANDLE dumpFileDescriptor = CreateFileA(mmFileName, 2 GENERIC_READ | GENERIC_WRITE, 3 FILE_SHARE_READ | FILE_SHARE_WRITE, 4 NULL, 5 OPEN_EXISTING, 6 FILE_ATTRIBUTE_NORMAL, 7 NULL); 8 HANDLE fileMappingObject = CreateFileMapping(dumpFileDescriptor, 9 NULL, 10 PAGE_READWRITE, 11 0, 12 0, 13 NULL); 14 void* mappedFileAddress = MapViewOfFile(fileMappingObject, 15 FILE_MAP_ALL_ACCESS, 16 0, 17 0, 18 MMAP_ALLOCATOR_SIZE); 19 20 // Do something use mappedFileAddress
同步數據到磁盤
1 FlushViewOfFile(mappedFileAddress, MMAP_ALLOCATOR_SIZE);
解除映射
1 UnmapViewOfFile(mappedFileAddress);
Windows上如果想要刪除映射文件的話,要先把文件Handle關掉,我一開始不知道這個,怎么刪也刪不掉。
1 CloseHandle(fileMappingObject); 2 CloseHandle(dumpFileDescriptor); 3 unlink(mmFileName);
兩個平台跑起來的效果稍有差別,win32上假如你在heap上申請50M內存(別的什么也不干),把這50M映射了以后可以發現,程序運行時程序占用內存只有幾百K,也就是說映射了的內存就跑到磁盤中去了,不占內存空間了,前提是你沒有訪問這50M空間。Linux上同樣的程序,50M還會在內存中,即使你沒有訪問過它也會在內存里有備份,但是如果你申請的內存很大,比如100M,200M的時候才會釋放掉內存空間。我想可能原因是在linux上,只有內存真正不夠用時,系統才會把映射到文件中的內存空間釋放吧,而windows上只要映射了文件,那么就會釋放掉內存,除非你訪問它。
