- Last update:

Understanding The Memory

Understanding how memory works

🕒 4 min read

Category: Computers

Tags: code, computer, memory

Understanding memory management can be a bit difficult for beginners. However, it's still one of the most important things every developer should know. You'll need to know how it works to write memory-efficient code, to avoid stack overflows. This is especially true when developing for mobile platforms that have very limited memory. Today's cheapest smartphones have an average of 512MB memory. Android will kill any app that consumes too much memory with even warning you. So be careful beforing allocating too many objects.

Nows, let's have a look at memory and let's try to understand how it works.

Processes and threads

Basically, when a program is launched, the operating system grants it a certain space in memory. The allocated memory contains four main areas:

The stack
Image taken from http://www.linuxjournal.com/article/6391
int add(int a, int b) {
    return a + b;
}

int main() {
    int c = add(1,2);
    return 0;
}

Let's see how this code gets compiled in x86 assembly.

gcc -S -masm=intel main.c -fno-asynchronous-unwind-tables -o output.asm

Now, we'll see the instructions using the stack.

    .file   "main.c"
    .intel_syntax noprefix
    .text
    .globl  add
    .type   add, @function
add:
    push    rbp
    mov rbp, rsp
    mov DWORD PTR [rbp-4], edi
    mov DWORD PTR [rbp-8], esi
    mov edx, DWORD PTR [rbp-4]
    mov eax, DWORD PTR [rbp-8]
    add eax, edx
    pop rbp
    ret
    .size   add, .-add
    .globl  main
    .type   main, @function
main:
    push    rbp
    mov rbp, rsp
    sub rsp, 16
    mov esi, 2
    mov edi, 1
    call    add
    mov DWORD PTR [rbp-4], eax
    mov eax, 0
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
    .section    .note.GNU-stack,"",@progbits

Threads can be seen as sub-processes, although they belong to a specific process. Thus, they share the same virtual space (same data segment, etc). Only one thing is unique to each thread: they all have their own stack.

Allocating memory for objects and primitive data types

C++

Every dynamic allocation goes to the heap. The rest on the stack. So every left handside part of the following lines (what is on the left of the equal sign) is on the stack.

Global variables and static variables (not only global) go to the data segment.

Here are some examples, to make things clear:

void fonction() {
  Object o(); // On the stack
  Object o2 = Object(); // On the stack
  Object& ref = o; // The reference is on the stack
  Object* pt = &o; // The pointer is on the stack
  Object* pt2 = new Object(); /* The right handside (the actual object)
    is on the heap, the left handside is on the stack */

  /* Everything that has been allocated on the stack will be
    deleted at the end of the function */
}

To delete what is on the heap, you need to use the delete keyword.

Pointers and addresses

Java

The main difference is that objects on the heap are automatically destroyed by the garbage collector, once they are no longer referenced. Moreover, only primitives are on the stack. All the objects are allocated on the heap. However, references (which are addresses) are passed as arguments to functions on the stack.

That's all folks!

Further reading