Hi,
Freanan wrote:
But wouldn't a system call, called "commit" for example, which
is only responsible for the mapping/setting to present,
but not (like traditional sbrk/morecore) for the actual allocation/accounting business, also
solve the pagefaulting-problems of demand paging?
First, forget about heap management for now (I get to it further down).
Using a system call like "commit" to allocate N pages at once would be faster than using allocation on demand (with N page faults) if every page allocated is actually used, because there's much less overhead.
Using a system call like "commit" to allocate one page at a time wouldn't be faster than using allocation on demand, because they'd both be doing roughly the same thing. In this case, allocation on demand would be easier to write software for because you don't need to write the code to allocate each page, but "commit" would catch more bugs (a messed up pointer would cause a page fault rather than an allocation).
Using a system call like "commit" to allocate N pages at once would waste RAM compared to allocation on demand if all pages aren't actually used. For example, if only one page is actually used then "N - 1" are wasted. Because of this "commit" can also increases the chance that the OS will run out of RAM and swap space will be needed (in this case "commit", or the additional swap space, can have a horrible effect on performance). Even if swap space doesn't become needed it'd still effect the amount of RAM that's left over for things like file system caches (wasting RAM can effect performance in other ways).
Therefore, for areas that are actually used it's better for performance to use "commit" (pre-allocate RAM), but for areas where some pages might not actually be used it's probably better to use allocation on demand.
Now, how can the kernel/OS determine which pages an application may or may not actually use in advance? It can't - often the application doesn't even know (compare "gcc --help" to "gcc myHugeProject"). The only way to get the best "efficiency" (ie. the best compromise between wasted RAM and speed) is to allow the application to control how pages are allocated for each area at run time.
This means you'd need a linear memory manager that allows the application to specify the "page types" used for each area.
For everything above, the term "application" actually means the entire application, including any libraries that it uses. For example, "allow the application to control how pages are allocated" actually means "allow the application and/or the libraries that it uses to control how pages are allocated".
As for the heap manager (malloc(), realloc(), free(), etc), it should be built on top of the linear memory manager (typically as part of a standard library in user space), and should use the facilities provided by the linear memory manager. For functions like brk() and sbrk(), implement them on top of the linear memory manager too (if they're needed), just like the heap memory manager itself.
This allows different heap managers to be used that are "tuned" to the application, or heap managers that support extra features. It also allows other memory management things to be implemented (like "obstacks"), or for the application to do it's own memory management without any of these - e.g. using the linear memory manager's interface directly without any "assistance" (which can be important for highly tuned applications like a large databases).
Cheers,
Brendan