Question

I have been optimising memory performance on a Windows Mobile application and have encountered some differences in behaviour between VirtualAlloc on Win32 and Windows CE.

Consider the following test:

// Allocate 64k of memory
BYTE *a = (BYTE*)VirtualAlloc(0,       65536,
                              MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
// Allocate a second contiguous 64k of memory
BYTE *b = (BYTE*)VirtualAlloc(a+65536, 65536,
                              MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);

BYTE *c = a + 65528; // Set a pointer near the end of the first allocation
BOOL valid1 = !IsBadWritePtr(c, 8); // Expect TRUE
BOOL valid2 = !IsBadWritePtr(c+8, 4088); // Expect TRUE
BOOL valid3 = !IsBadWritePtr(c, 4096); // TRUE on Win32, FALSE on WinCE

The code "allocates" 4096 of data starting at "c". On Win32 this works. I can find no mention in the VirtualAlloc documentation whether it is legal or coincidence but there are many examples of code that I have found via google that expect this behaviour.

On Windows CE 5.0/5.2 if I use the memory block at "c", in 99% of cases there are no problems, however on some (not all) Windows Mobile 6 devices, ReadFile & WriteFile will fail with error 87 (The parameter is incorrect.). I assume ReadFile is calling IsBadWritePtr or similar and return false due to this. If I perform two ReadFile calls then everything works fine. (There may of course be other API calls that will also fail.)

I am looking for a way to extend the memory returned by VirtualAlloc so that I can make the above work. Reserving a large amount of memory on Windows CE is problematic as each process only gets 32MB and due to other items being loaded it is not possible to reserve a large region of memory without causing other problems. (It is possible to reserve a larger amount of memory in the shared region but this also has other problems.)

Is there a way to get VirtualAlloc to enlarge or combine regions without reserving it up front?

I suspect it may be problematic given the following examples:

HANDLE hHeap1 = HeapCreate(0, 0, 0); // Heap defaults to 192k
BYTE * a1 = (BYTE*)HeapAlloc(hHeap1, 0, 64000); // +96 bytes from start of heap
BYTE * b1 = (BYTE*)HeapAlloc(hHeap1, 0, 64000); // +16 bytes from end of a1
BYTE * c1 = (BYTE*)HeapAlloc(hHeap1, 0, 64000); // +16 bytes from end of b1
BYTE * d1 = (BYTE*)HeapAlloc(hHeap1, 0, 64000); // +4528 bytes from end of c1

HANDLE hHeap2 = HeapCreate(0, 4*1024*1024, 4*1024*1024); // 4MB Heap
BYTE * a2 = (BYTE*)HeapAlloc(hHeap2, 0, 64000); // +96 bytes from start of heap
BYTE * b2 = (BYTE*)HeapAlloc(hHeap2, 0, 64000); // +16 bytes from end of a2
BYTE * c2 = (BYTE*)HeapAlloc(hHeap2, 0, 64000); // +16 bytes from end of b2
BYTE * d2 = (BYTE*)HeapAlloc(hHeap2, 0, 64000); // +16 bytes from end of c2
Was it helpful?

Solution

No, it's not possible.

OTHER TIPS

I wouldn't trust IsBadWritePtr, see this: http://support.microsoft.com/kb/960154 I think it does something like tries to write to the memory, and sees if it gets a hardware exception. It handles the exception and then returns true or false. But, I've heard that some hardware will only raise an exception once for an attempt to write to one page, or something like that.

Is it not possible for you to VirtualAlloc without a MEM_COMMIT, so you just reserve the virtual memory addresses. Then when you actually want to use the memory, call VirtualAlloc again to do the commit. As you already reserved the pages, you should be able to commit them contiguously.

You say you want to do it without reserving up front. But, what's wrong with reserving up front. Reserving doesn't actually use any physical memory, it reserves a range of virtual addresses, it'll only use physical memory when you commit the pages.

Ah, ok. In that case have you heard of the large memory area, I think that's Microsoft's workaround/fix to your problem.

Basically, if you VirtualAlloc more than 2 meg, it goes into the large memory area of the virtual memory and this lets you exceed the 32mb limit.

There's quite a good discussion of how it all works here:
http://msdn.microsoft.com/en-us/library/ms836325.aspx

I used it myself on a previous product, and it did the trick for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top