I have an app with a number of worker threads, one for each core. On a modern 8 core machine, I have 8 of these threads. My app loads a lot of plugins, which also have their own worker threads. Because the app uses huge blocks of memory (photos, eg. 200 MB) I have memory fragmentation problem. The problem is that every thread allocates the {$MAXSTACKSIZE ...} of address space. It's not using the physical memory but the adress space. I reduced the MAXSTACKSIZE from 1MB to 128KB and it seems to work, but I don't now if I'm near to the limit. Is there any possibility to measure how much stack is really used?
相关问题
- Is there a Delphi 5 component that can handle .png
- Is there a way to install Delphi 2010 on Windows 2
- Is TWebBrowser dependant on IE version?
- iOS objective-c object: When to use release and wh
- DBGrid - How to set an individual background color
相关文章
- Threading in C# , value types and reference types
- Best way to implement MVVM bindings (View <-> V
- Windows EventLog: How fast are operations with it?
- Stack<> implementation in C#
- How to force Delphi compiler to display all hints
- Coloring cell background on firemonkey stringgrid
- HelpInsight documentation in Delphi 2007
- Java, Printing the stack values
Reducing $MAXSTACKSIZE won't work because Windows will always align thread stack to 1Mb (?).
One (possible?) way to prevent fragmentation is to reserve (not alloc!) virtual memory (with VirtualAlloc) before creating threads. And release it after the threads are running. This way Windows cannot use the reserved space for the threads so you will have some continuous memory.
Or you could make your own memory manager for large photo's: reserve a lot virtual memory and alloc memory from this pool by hand. (you need to maintain a list of used and used memory yourself).
At least, that's a theory, don't know if it really works...
Whilst I am sure that you can reduce the thread stacksize in your app, I don't think it will address the root cause of the problem. You are using an 8 core machine now, but what happens on a 16 core, or a 32 core etc.
With 32 bit Delphi you have a maximum address space of 4GB and so this does limit you to some degree. You may well need to use smaller stacks for some or all of your threads, but you will still face problems on a big enough machine.
If you help your app scale better to larger machines you may need to take one or other of the following steps:
Use this to compute the amount of memory committed for the current thread's stack:
Another idea I don't have.
For the sake of completeness, I am adding a version of the
CommittedStackSize
function provided in opc0de's answer for determining the amount of used stack that will work both for x86 32- and 64-bit versions of Windows (opc0de's function is for Win32 only).opc0de's function queries the address of the base of the stack and the lowest committed stack base from Window's Thread Information Block (TIB). There are two differences among x86 and x64:
FS
segment register on Win32, but by theGS
on Win64 (see here)Additionally note that there is a small difference in the BASM code, because on x64,
abs
is required to make the assembler use an absolute offset from the the segment register.Therefore, a version that will work on both Win32 and Win64 version looks like this:
I remember i FillChar'd all available stack space with zeroes upon init years ago, and counted the contiguous zeroes upon deinit, starting from the end. This yielded a good 'high water mark', provided you send your app through its paces for probe runs.
I'll dig out the code when i am back nonmobile.
Update: OK the principle is demonstrated in this (ancient) code:
(From http://webtweakers.com/swag/MEMORY/0018.PAS.html)
I faintly remember having worked with Kim Kokkonen at that time, and I think the original code is from him.
The good thing about this approach is you have zero performance penalty and no profiling operation during the program run. Only upon shutdown the loop-until-changed-value-found code eats up CPU cycles. (We coded that one in assembly later.)
Even if all 8 threads were to come close to using their 1MB of stack, that's only 8MB of virtual memory. IIRC, the default initial stack size for threads is 64K, increasing upon page-faults unless the process thread-stack limit is reached, at which point I assume your process will be stopped with a 'Stack overflow' messageBox :((
I fear that reducing the process stack limit $MAXSTACKSIZE will not alleviate your fragmentation/paging issue much, if anything. You need more RAM so that the resident page set of your mega-photo-app is bigger & so thrashing reduced.
How many threads are there, overall, on average, in your process? Task manager can show this.
Rgds, Martin