Win32 Programming - Richard Ford
Download
Report
Transcript Win32 Programming - Richard Ford
Win32 Programming
Lesson 18: More Memory Mapped Files and
the HEAP
(Finally, cool stuff!)
Where are we?
We’ve gotten pretty familiar with the idea of
memory-mapped files but there are some
important concepts we haven’t looked at
Finish up today, and then look at the heap
Sharing Data
There are lots of different ways to share data
between processes
But the “lowest level” way is really in
memory, via a memory-mapped file
Two or more processes map the same base
address – hence they are sharing the same
physical memory
Avoiding the “real” File system
Very inconvenient if every memory-mapped
file actually had to exist on disk
Imagine that you simply wanted to use the
mechanism to pass data, not keep it
Can call CreateFileMapping with
INVALID_HANDLE_VALUE as the hFile
parameter, and the memory-mapped file is backed
by the page file
30 Second Quiz
What’s wrong with this code?
HANDLE hFile = CreateFile(...);
HANDLE hMap = CreateFileMapping(hFile,
...);
if (hMap == NULL)
return(GetLastError());
Answer…
You’ll get back
INVALID_HANDLE_VALUE from the first
call
Which means…
MMFExample
Simple program
When it maps the view of the file, it transfers
data between the two programs
Nice method of sharing between two
processes!
Sparsely Committing…
Remember we talked about how to commit
memory for files?
Same discussion for Memory-mapped files –
that is, we don’t need to commit all our
memory at once
Consider
CELLDATA CellData[200][256];
If sizeof(CELLDATA) is 128 that’s about
6MB.
Better to share as a sparsely-committed file
mapping object
If we’re sharing via the paging file, can use
SEC_RESERVE or SEC_COMMIT
SEC_RESERVE
When you pass in SEC_RESERVE you don’t
actually commit the space
Just returns a HANDLE to the file mapping
object
Any attempts to access the memory cause a
memory violation
VirtualAlloc (again)
Solution: Call VirtualAlloc to allocate the
memory as we use it!
The HEAP
Heap is a fantastic tool for allocating small
blocks of memory
Perfect for linked lists and trees
Advantage: can ignore allocation granularity
Disadvantage: slow, with no direct control of
physical allocation
Better yet, internals not entirely documented
Default
Each process gets a default heap of 1MB
Can specify at link time (/HEAP:)
Used by many Windows/C RTL functions
Access to the HEAP is serialized (why, and
what does this mean?)
Can obtain a handle via:
HANDLE GetProcessHeap();
More than 1 Heap is a…
Five reasons you might want to do this:
Component protection
More efficient memory management
Local access
Avoiding thread sync overhead
Quick free
1: Component Protection
Imagine you have two structures: a linked list
and a binary tree
If you share one heap, and one has a bug, the
problem may show up in the other structure
If we have different heaps, problems tend to
be localized (unless you *really* mess up!)
2: Memory Management
Heaps work best when all the objects in them
are the same size
Imagine mixing two different sizes; when you
free object 1 object 2 may not be a perfect fit
Better to allocate all objects of the same size
in the same place
3: Local Access
Swapping to disk is really expensive
Best to keep things you use together close
together
4: Avoiding thread-sync issues
Heaps are serialized by default
CPU overhead involved in keeping heap
access thread safe
If you tell the system a heap is singlethreaded, you can lose this overhead
DANGER WILL ROBINSON: YOU ARE NOW
RESPONSIBLE FOR THREAD SAFETY!!!
5: Quick free
Instead of freeing things up block by block
you can choose to free the entire heap in one
go
That’s *really* quick
So… how?
HANDLE HeapCreate(
DWORD fdwOptions,
SIZE_T dwInitialSize,
SIZE_T dwMaximumSize);
Options: 0, HEAP_NO_SERIALIZE,
HEAP_GENERATE_EXCEPTIONS
Serialize turns off checking for Alloc and Free
Can manage this yourself via Critical Sections if you
want to
HEAP_GENERATE_EXCEPTIONS
Raise an exception whenever an allocation
request fails
Basically, it’s just about whether you want to
catch exceptions or check return values –
depends on the application
Oh… if dwMaximumSize is 0 the size is
unlimited…
Allocating Memory from the Heap
PVOID HeapAlloc(
HANDLE hHeap,
DWORD fdwFlags,
SIZE_T dwBytes);
Flags: HEAP_ZERO_MEMORY,
HEAP_GENERATE_EXCEPTIONS,
HEAP_NO_SERIALIZE
Exceptions: STATUS_NO_MEMORY,
STATUS_ACCESS_VIOLATION
Changing the size…
PVOID HeapReAlloc(
HANDLE hHeap,
DWORD fdwFlags,
PVOID pvMem,
SIZE_T dwBytes);
New flag:
HEAP_REALLOC_IN_PLACE_ONLY
Means that the location won’t change
Obtaining the Size
SIZE_T HeapSize(
HANDLE hHeap,
DWORD fdwFlags,
LPCVOID pvMem);
Flags: 0 or HEAP_NO_SERIALIZE
Freeing a block
BOOL HeapFree(
HANDLE hHeap,
DWORD fdwFlags,
PVOID pvMem);
Flags? You tell me…
Destroying a Heap
BOOL HeapDestroy(HANDLE hHeap);
TRUE on success
You can’t destroy the default heap!
Heaps with C++
Under C you would use malloc
In C++ can use new/delete
CSomeClass *pSomeClass = new CSomeClass;
delete pSomeClass;
Now the clever bit: overload new/delete…
Prototype
class CSomeClass {
private:
static HANDLE s_hHeap;
static UINT s_uNumAllocsInHeap;
// Other private data and member functions
public:
void* operator new (size_t size);
void operator delete (void* p);
// Other public data and member functions
};
Code…
HANDLE CSomeClass::s_hHeap = NULL;
UINT CSomeClass::s_uNumAllocsInHeap = 0;
void* CSomeClass::operator new (size_t size) {
if (s_hHeap == NULL) {
// Heap does not exist; create it.
s_hHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
if (s_hHeap == NULL)
return(NULL);
}
// The heap exists for CSomeClass objects.
void* p = HeapAlloc(s_hHeap, 0, size);
if (p != NULL) {
// Memory was allocated successfully; increment
// the count of CSomeClass objects in the heap.
s_uNumAllocsInHeap++;
}
// Return the address of the allocated CSomeClass object.
return(p);
}
And delete…
void CSomeClass::operator delete (void* p) {
if (HeapFree(s_hHeap, 0, p)) {
// Object was deleted successfully.
s_uNumAllocsInHeap--;
}
if (s_uNumAllocsInHeap == 0) {
// If there are no more objects in the heap,
// destroy the heap.
if (HeapDestroy(s_hHeap)) {
// Set the heap handle to NULL
// so that the new operator
// will know to create a new heap if a
// new CSomeClass
// object is created.
s_hHeap = NULL;
}
}
}
Misc Functions…
DWORD GetProcessHeaps – returns handles to all
heaps in the process
BOOL HeapValidate – check that a heap is a-okay…
UINT HeapCompact – coalesce free blocks
HeapLock and HeapUnlock – used for thread sync
HeapWalk – for debugging; lets you enumerate
sections/blocks in the heap
Next
Next, it gets difficult
DLLs