tags:

views:

103

answers:

3

Hello guys,

I have questions regarding stacks and dynamic memory allocation.

1) Does kernel determine the size of the stack dynamically during run time or sets the size before the load time ? If stack size is allocated dynamically how can stack overflow take place (Because if size of stack reaches beyond the limit the page handler will allocate space to grow the stack). Also If dynamically allocated how can stack grow from higher address to lower address(because always the virtual address increments for dynamically allocated storage right?)

2) Also if memory is allocated dynamically using malloc the size of the data region grows right ?

Thanks & Regards,

Mousey.

A: 

1) Dynamic memory allocation is from the heap, not the stack. The stack is a per-thread block of memory that also handles local variables and return addresses during function calls. The heap is just one or more blocks of memory allocated from the OS, which the C RTL subdivides as needed to satisfy malloc calls.

As for the stack, it's typically of a fixed size because, in a program free of infinite recursion, you should only need a finite amount. If you keep recursing, you'll overflow, which is a good thing in that it's a clean failure. As for growing down in memory, that's an implementation detail of CPU's.

2) Not necessarily. So long as the current allocation of memory from the OS is sufficient, malloc just uses it. Once this is gone, it may cause an additional allocation.

I know you want more detail here, but I'm not sure what's useful. I could talk about how the heap is typically implemented as linked lists of free blocks with arena headers that define their size, or how some systems use fixed-size blocks for small allocations to limit fragmentation, or even how memory bubbles are coalesced when no single sufficiently large block is found. However, all of these are implementation details that may well turn out not to apply in your case, at least not exactly.

Steven Sudit
1) I am not asking about C dynamic memory allocation ! The question is about how stacks are allocate by the kernel. How does kernel know about the size of the stack !2) Can you explain in more detail pls.
mousey
1) The usual way is for a thread to be assigned a fixed block of memory to use as its stack.
Steven Sudit
For every thread the size of the stack is same ? This is a waste of space right ?
mousey
Not really, and it depends on the OS. For example, Windows grants a thread 1M of address space. However, it only doles it out in 4K chunks, so unused memory range beyond that is never backed up by any memory.
Steven Sudit
Memory *can* be dynamically allocated on the stack. See `alloca`, or variable-length arrays. It's just not usually done.
Thom Smith
@Steven I am looking for implementation details of heap. According to your explanation heap is a pool of memory allocated by os and is it is allocated per process ? If it per process then the only way the size of process can increase is by incrementing the data segment of the process right ?
mousey
The heap is allocated by the C RTL *from* the OS. The details are implementation-dependent, however, so anything I tell you will apply only to some cases, not others. The heap is definitely per-process, but it may well allocate a range of memory without initially committing physical memory to the pages. I have no idea what you mean by "data segment" in this context, though.
Steven Sudit
@Thom: You're correct, of course, on both counts.
Steven Sudit
In unix there is a function in kernel called growreg which increments the size of the virtual memory with restrictions. Both brk and mmap are implemented using this function. I think in Windows there is heap manager which allocates memory and attaches it to a process ?(some one clarify about this please)
mousey
I don't think I can adequately summarize how it works under Windows in this short space. Let's just say it's different from Unix.
Steven Sudit
+1  A: 

Stack sizes

Typically, each thread has a fixed stack when the thread is created. Run ulimit -a to see the default stack size for your system. On my system, it is 8 MiB. When you create new threads, you can give them smaller or larger stacks (see pthread_attr_setstacksize).

When the stack grows beyond 8 MiB, the program will write to an invalid memory location and crash. The kernel makes sure that the memory locations next to the stack are all invalid, to ensure that programs crash when their stacks overflow.

You may think that a fixed size is a waste, but that 8 MiB is virtual memory and not physical memory. The difference is important, see below.

Malloc

On Unix systems, memory allocation has two layers to it. The user-space layer is malloc (and calloc, realloc, free). This is just part of the C library, and can be replaced with your own code -- Firefox does this, and many programming languages use their own allocation scheme other than malloc. Various malloc implementations are cross-platform.

The lower layer is mmap (and sbrk). The mmap function is a system call which alters your program's address space. One of the things it can do is add new anonymous, private pages into your program's memory.

The purpose of malloc is to get large chunks of virtual memory from the kernel using mmap (or sbrk) and divide them up efficiently for your program. The mmap system call only works in multiples of 4 KiB (on most systems).

Memory: virtual versus real

Remember that the stack and all of the memory returned by mmap is just virtual memory, not physical RAM. The kernel doesn't allocate physical RAM to your process until you actually use it.

When you get anonymous memory from the kernel, either on the heap or the stack, it's filled with zeroes. Instead of giving you hundreds of pages of physical RAM pre-filled with zeroes, however, the kernel makes all of that virtual memory share one single page of physical RAM. The virtual memory is marked read only. As soon as you write to it, the CPU throws an exception, transfers control to the kernel, and the kernel allocates a fresh, writable, zeroed page for your program.

This explains why:

  • calloc is faster than malloc + memset (because calloc knows that the mmap'd pages are pre-zeroed, and memset forces the allocation of physical RAM)
  • You can allocate much more memory than combined RAM + swap (because it's not used until you write to it)
Dietrich Epp
@Dietrich Thank you very much for the reply .so whenever malloc uses sbrk or mmap the memory is attached to which region ?(data,stack or text). It should be data right ?
mousey
Interesting, but much of this only applies to Unix.
Steven Sudit
@Steven Windows doesnt differentiate between regions ? Generally its is done in the executable (PE in windows). So system can impose restrictions ( ex: marking text or code as read only or if system going beyond a particular region it gives an exception)
mousey
Windows differs in the details. There is no `mmap` or `sbrk`, but there is memory mapping.
Steven Sudit
@Steven: Question was tagged "Unix", hence the Unix-specific answer. @mousey: Your executable's sections are mapped into virtual memory, and when you call "mmap", you are creating new mappings, not extending old mappings.
Dietrich Epp
@Dietrich: Fair enough, but there's no actual obligation for a Unix variant to offer precisely this scheme. My point here, overall, is that it's more important to understand the parts that are universal than to specialize in an implementation detail that's both variable and subject to change. Your code shouldn't be so bound to such details that it becomes brittle.
Steven Sudit
@Steven: mmap and sbrk are universal, on Unix platforms. The important differences between allocated virtual memory and allocated physical RAM are also universal, not variable, and not subject to change, on Unix platforms.
Dietrich Epp
@Deitrich: There have been Unix platforms without such a distinction, simply because the hardware didn't support it.
Steven Sudit
+2  A: 

1) It kind of depends on the OS, but a typical scheme is for the OS to give you one page of virtual memory (pages are commonly 4 KB) for the stack and then marks the virtual memory page immediately after it as a "guard page." This is a special flag that causes a low-level exception to trigger when an application tries to write into it.

The OS handles the exception when you try to write into the guard page (which happens as you grow the stack past the initial allocation size), allocates that page for you (i.e. maps it to a physical memory page), and reruns your program from the instruction where the faulting write occurred. It will work this time since the page has been backed by real memory.

Past a certain point (commonly 1 MB), the OS will stop doing this and trigger a stack overflow exception. This is just because these are usually indicative of program error, and code that really needs huge stacks can allocate memory for whatever their stack data is on the heap.

2) The data segment doesn't really "grow." Modern programs have a fixed virtual memory address space. malloc() uses some scheme to carve up this space and back portions of it with real physical memory.

I think both of your questions hint at wanting a better understanding of how the OS provides physical memory to your programs. The key concept in modern systems is virtual memory. Wikipedia's page on virtual memory is a good place to start.

If you want to develop detailed knowledge, an OS textbook would be a good place to start. Preferably one that's better than whatever I had when I took that OS course in college :)

fastcall
@fastcall Thank you very much for the reply. Also I am reading a OS book it says malloc allocates space on swap space so I asked the question in a different way.
mousey
"malloc" doesn't map physical memory into your process, instead, the kernel does that once you write to the memory returned by malloc. You can experiment for yourself: even if you malloc hundreds of megs, the amount of used physical RAM won't increase.
Dietrich Epp
@Dietrich So it should be mapped to my virtual address right ? Other wise program doesnt work!
mousey
@mousey: mmap typically won't map physical RAM into your virtual addresses. It merely records a "promise" for the kernel to map physical RAM into your program if you write into it. If you never use the virtual memory, the kernel won't allocate the physical RAM to back it.
Dietrich Epp