Memory mapping files uses the operating system's virtual memory capabilities to provide rapid access to files without allocating in-memory buffers. File contents appear as a region of memory and are accessed by dereferencing an ordinary pointer.
Object Pascal provides a number of very useful facilities for operating on files. Files may be accessed by character, line, fixed-length records, or one of the most popular methods: file streams. Memory mapping files provides an additional technique that one may find optimal under certain circumstances. This paper will give a brief introduction to memory mapping and discuss a cross-platform object and interface for mapping files on both Linux and Windows.
Most developers have a general understanding of virtual memory. Many people usually associate virtual memory with the CPU's ability to access more address space than physically exists. Virtual memory has many other interesting facets which are beyond the scope of this paper.
The term memory mapping files refers to the ability of an operating system to redirect memory access to a section of a file on disk. A program sees a mapped file as a pointer. The valid region of memory that the pointer points to corresponds directly to the bytes in the mapped file. Reading and writing memory relative to the pointer reads and writes the corresponding bytes in the mapped file. Figure one depicts the file foo.txt mapped into a process' memory at location $0123000.
|
| Figure 1 |
Memory mapping has some distinct strengths that one ought to keep in mind when choosing a file access method.
As with everything, there are drawbacks to consider.
Mapping and unmapping a file is operating-system dependent. This section describes the system calls requried to perform memory mapping with Kylix.
uses Libc;
. . .
const
INVALID_HANDLE = -1;
. . .
sb :TStatBuf;
FSize :Integer;
FData :Pointer;
. . .
if stat(PChar(FileName), sb)=0 then
FSize := sb.st_size
else
... // Fail; can't stat (retrieve information about) the file.
Note that the
open()
system call determines whether the mapping is readable and/or writable.
The parameters passed to
mmap()
must not conflict with the access requested during
open().
See the man pages for
mmap()
for more information.
fd := open(PChar(FileName), O_RDWR);
if fd=INVALID_HANDLE then ... // Fail; cannot open file
mmap()
. Note that one needs to supply the size of the file as the number of bytes to map.
FData :Pointer;
. . .
FData := mmap(nil, FSize, PROT_READ or PROT_WRITE, MAP_SHARED, fd, 0);
if FData=MAP_FAILED then ... // Fail; cannot create file mapping
When one is done with a mapped file, one must unmap the file.
msync(FData, FSize, MS_SYNC);
munmap(FData, FSize);
__close((fd);
Mapping and unmapping a file is operating-system dependent. This section describes the system calls requried to perform memory mapping with Delphi.
. . .
FSize :Integer;
hFile :THandle;
hMap :THandle;
. . .
// Sanity check
if not FileExists(FileName) then ... // Fail; File not found.
// Get Win32 file handle
hFile := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if hFile=INVALID_HANDLE_VALUE then ... // Fail; Cannot open file.
// Get size of file
FSize := Windows.GetFileSize(hFile, nil);
// Create memory map of file for direct access hMap := CreateFileMapping(hFile, nil, PAGE_READWRITE, 0, 0, nil); if hMap=INVALID_HANDLE_VALUE then ... // Fail; Cannot create file mapping. FData := MapViewOfFile(hMap, FILE_MAP_READ or FILE_MAP_WRITE, 0, 0, 0); if FData = nil then ... // Fail; Cannot map view of file.
When one is done with a mapped file, one must unmap the file.
if FData<>nil then
begin
FlushViewOfFile(FData, 0); // This is needed if changes were made.
UnmapViewOfFile(FData);
end;
if hMap<>INVALID_HANDLE_VALUE then CloseHandle(hMap);
if hFile <> INVALID_HANDLE_VALUE then CloseHandle( hFile );
| Pat Felt | Pointed out typos in this document. |
| Dennis Passmore | Pointed out bad Windows bug.
Pointed out the fact that only files up to 2GB can be addressed by the sample code. This is due to the limitations of the Intel IA32 architecutre, and was something that I knew about but never made explicit. Comment added to header to warn about this assumed knowledge. |
| Ray Lichner | Pointed out small inefficiencies in the code. |
If one plans on using memory mapping, it's always nice to have an easy-to-use wrapper. Please e-mail me if you find any bugs so others may benefit!
Version History: