Stack vs Heap

Stack Heap
Stored in RAM Stored in RAM
Has limited size The size is dynamic and can be increased
There is 1 stack for each Thread There is 1 heap for the Application(usually)
Stack is reclaimed when a Thread exits Heap is reclaimed when an App exits
Stack is faster, because an allocation and deallocation is simply a pointer moving(trivial push/pop operations) Heap is slower because of more complex allocation/deallocation
Stack is a memory allocated for a thread of execution; LIFO Heap is a memory allocated dynamically
On function call a block is reserved on top of the stack for local variables, when function returns the block is freed

In C++ malloc, calloc and new are used to allocate memory on the heap and it's responsible for memory leaks if not manually deallocated. C++ heap memory leak example:

int foo()
{
  char *pBuffer; // Nothing allocated yet (excluding the pointer itself, which is allocated here on the stack)
  bool b = true; // Allocated on the stack
  if(b)
  {
    // Create 500 bytes on the stack
    char buffer[500];

    // Create 500 bytes on the heap
    pBuffer = new char[500];

   } // <- Buffer is deallocated here, pBuffer is not
} // <- Oops there's a memory leak, I should have called delete[] pBuffer;

In Go a compiler might choose to allocate local variables on the heap or on the stack, but contrary to C++ the choice is not determined by whether var or new was used to declare the variable.

var global *int

func f() {
  var x int
  x = 1
  global = &x
}

Here, x must be heap-allocated because it is still reachable from the variable global after f has returned, despite being declared as a local variable; we say x escapes from f.

func g() {
  y := new(int)
  *y = 1
}

Conversely, when g returns, the variable *y becomes unreachable and can be recycled. Since *y does not escape from g, it's safe for the compiler to allocate *y on the stack, even though it was allocated with new. In any case, the notion of escaping is not something that you need to worry about in order to write correct code, though it's good to keep in mind during performance optimization, since each variable that escapes requires an extra memory allocation.

Here is another example of the local variable within the function which escapes:

func main() {
  s := sum(1, 2, 3, 4, 5)
  fmt.Println("The sum is ", *s)
}

func sum(values ...int) *int {
  result := 0
  for _, v in range values {
    result += v
  }
  return &result
}