Quote:
Originally posted by OReubens
I seem to have missed this in my usual looking around here, and I just picked this up on the 'hot topics' :-) Allow me to share some of my experiences on this matter...
On 'regular' Windows, each process you start, has at it's disposal a memoryspace of 2^32 bytes. Part of this memory is reserved for windows kernel code and data (Usually everything from 0x80000000 to 0xFFFFFFFF) giving you 2 GB of breathing room for your application.
On Win2K server there is a setting which will change this slightly to give applications 3Gb of breathing room, leaving 'only' 1Gb for kernel code/data. Not all programs will run properly if you enable the setthing however. Look around on MSDN for more details on this matter.
Now... Having 2Gb of adressable memory space doesn't mean you will be able to allocate that much memory. Since part of that memory will be occupied with your programs code (usually starting at 0x00400000), stack, and the code of DLL's you've loaded. Most of the time, the 2gb will be fragmented to some degree and this may prevent you from allocating large chunks of memory at once.
It's entirely possible that while you have 1.5Gb of free memory, you won't be able to allocate a continuous chunk of say 1Gb, although you may be able to allocate 4 chunks of 256Mb. Especially for a server program that needs to run non-stop, this may end up being problematic if you do lots of allocates and frees. Fragmentation may end up preventing you from allocating memory, even though there's no leak, and there's enough 'free' memory. Just not continuous.
In one service I wrote, I ended up having to write my own low level memory allocation to prevent fragmentation from causing too much problems.
If you're allocating memory, you're also going to need either enough physical RAM or virtual RAM. Note that under WinNT/2000/XP, there is usually a limit to the effective pool. If your programs NEEDS large quantities of memory, you may have to change the settings. to allow for more virtual RAM.
Find this under: Control Panel, System, Advanced, Performance, Advanced (Obviously for extra advanced users :-)), Virtual Memory.
You should have the pool set sufficiently high to allow your program AND OTHER programs (and the Windows system itself) to run.
Note that If you end up using huge amounts of virtual memory, you can end up with a VERY slow program because of lots of paging.
If you're going to be needing lots of memory in your program, you're usually going to be wanting to have as much of that being actual RAM :-)
There are ways around the 2Gb (or 3Gb) limit...:
- Try using files for the memory, reading/writing the portions you need, when you need them. (basically, make your own 'virtual ram'/paging system). Quite often, if your program seems to need large amounts of RAM, it means you really need to use a database :-)
- Spawn multiple processes which will do nothing more than allocate and maintain additional memory for the 'main' program, each process will have 2Gb memoryspace. You can use some form of Interprocess communications (mailslots, pipes, sockets, Read/WriteProcessMemory(), DDE, ...) from your main program to the helper programs to obtain the memory you need.
- Switch to the new Win64. This gives processes a whopping 2^64 bits of address space (16 Exabyte, or 16 billion gigabytes), Again, half of that is reserved for the system, but even 8 exabyte should be more than enough. You're going to need a room full of RAM and/or harddisks to even HAVE that much in your machine ;-)
Of course, Win64 and a Win64 capable machine don't come cheap...
Each thread you create 'reserves' (not allocate/commit) a portion of memory for it's stack, the default is 1mb, but you can change the limit at the call to CreateThread(), After 2008 threads, each with 1mb of reserved stack, you will have more or less exhausted your 2Gb memory space, there is memory left, but no more continuous chunks of 1Mb.
Making this many threads is generally a bad idea anyway (although it's easy), you'll be having a lot of overhead (thread synchronising, thread context switching). It's better to have a limited number of working threads (if you can, try 1 per actual CPU), and use an internal queue of of requests/jobs.