When you discuss an App's memory space, you take into account a number of things and the heap is only one of them.
Because you already mentioned it, let's start with it. The heap is a dynamically allocated memory space. If you consider low-level languages like C/C++, when you call malloc(...)
or new Object(...)
, you allocate memory on the heap, when you free(...)
or delete X
, you free up the heap memory space.
An additional, very significant memory segment is the stack. As an oversimplification, this memory segment is responsible for "managing" the execution flow of our application and storing local variables. Because every thread in our process has its own execution flow, the operating system makes sure that every thread has its own stack. The default size of a Windows thread stack is 1MB.
Additional memory is occupied by additional segments of the application. Without going into much detail on those, Windows applications are PE files, and you can read about their format here and here. When you write your code, there are different things that are eventually stored into the binary file. The code itself is the most obvious component, but is not the only one. Static variables, some of which are initialized and some of which aren't (I won't go into detail to avoid confusion) are also part of the binary.
When you run the PE binary, the loader loads all those sections into the memory space of the created process. Over time, the application then creates new threads and allocates more memory.
As a gross and rough estimation, I would say that the amount of memory your process is using equals: heap + (thread-count * stack-size) + binary size
NOTE: I'm purposely ignoring advanced OS features, such as paging, lazy allocation, private heaps, etc.