Sergei wrote:
Thank you, Jeroen; it was nice of you to walk through all my questions. And
indeed, I had same assumptions with regard to LARGEADDRESSAWARE in DLL and
calling process. But there is a contradicting observation.
I have a large address aware C++ DLL (Enable Large Addresses is ON) and C#
winform executable whose header is not modified to access large addresses
2GB and <3GB (dumpbin \headers doesn’t say “Application can handle large
addresses”). The following code running inside of the DLL allows me to query
and to allocate virtual memory at 2GB and < 3GB addresses:
MEMORY_BASIC_INFORMATION memory_info;
memory_info.BaseAddress = NULL;
while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof
(memory_info)))
{
// Region is free, and it can be well aligned and big enough: we are done
if (memory_info.State == MEM_FREE )
BYTE * m_pDIB = (BYTE*)VirtualAlloc(
memory_info.BaseAddress // system selects address
, lRegionSize // page size, in bytes
, MEM_COMMIT // allocate a committed page
, PAGE_READWRITE); // read/write access
// Recompute BaseAddress
memory_info.BaseAddress = (char *) memory_info.BaseAddress +
memory_info.RegionSize;
}
I have no idea what you're trying to achieve here. Is this just
demonstration code or a simplified version of what you're actually using? It
certainly doesn't compile, and even with the obvious changes it seems pointless.
There's no point in looking for free memory yourself. If you want that, you
should simply pass NULL for the address in VirtualAlloc(). Also, you must
pass MEM_COMMIT | MEM_RESERVE if you want to both reserve and commit memory;
just specifying MEM_COMMIT only works if the memory is already reserved. If
you just want a big region of memory where you can do contiguous allocations
of your own, use MEM_RESERVE to reserve memory and MEM_COMMIT to commit
pages within that region.
I wrote a demonstration program of my own. It does a few VirtualAlloc()s
from both the main EXE and the DLL, freeing each intermediate result. The
results are consistent: the behavior of VirtualAlloc() depends *only* on
whether the executable is marked LAA; how the DLL is marked is irrelevant.
To be certain I repeated the test with a dynamically loaded DLL; the results
are the same.
Here's the output for a 32-bit app running on 64-bit Windows when the
executable is *not* marked /LARGEADDRESSAWARE:
VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN,
PAGE_READWRITE):
7EFA0000
VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
00520000
VirtualAlloc(0x01000000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
01000000
VirtualAlloc(0x81000000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
FAILED: Attempt to access invalid address.
---DLL---
VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN,
PAGE_READWRITE):
7EFA0000
VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
00520000
VirtualAlloc(0x01000000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
01000000
VirtualAlloc(0x81000000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
FAILED: Attempt to access invalid address.
And here's the output when the EXE *is* marked LAA:
---EXE---
VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN,
PAGE_READWRITE):
FFFA0000
VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
00520000
VirtualAlloc(0x01000000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
01000000
VirtualAlloc(0x81000000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
81000000
---DLL---
VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN,
PAGE_READWRITE):
FFFA0000
VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
00520000
VirtualAlloc(0x01000000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
01000000
VirtualAlloc(0x81000000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE):
81000000
Results were obtained on Windows Server 2003 R2 x64.
I want to know will managed code be able to fragment the large addresses and
is AWE is a better performance wise approach handling large memory in win32
application.
I don't know what you mean by "fragmenting" the addresses, but the CLR will
be able to access any memory you can allocate just fine.
As for AWE: don't bother. If you need >4G memory (which is really the point
where AWE becomes necessary) you should move to 64-bit and leave the
restrictions of 32-bit behind you altogether. I'm fairly certain the CLR has
no support for AWE, so managing it would have to be done entirely from
unmanaged code, which negates a lot of the advantages of garbage collection
(a big plus the CLR offers). Performance is not the issue here: simply being
able to use memory at all is.
--
J.
http://symbolsprose.blogspot.com