The musings and ramblings of a software craftsman

Let’s talk about memory!

As mentioned in the “About” section of the blog, I’m a developer and you could say I’m mainly focused on Java (though I’m interested in other languages such as Python, C++, Haskell and Scala) . One of the main reasons a lot of people choose Java is because it’s garbage collector, which, broadly speaking, is in charge of counting references to the variables in your program and, makes sure the memory they use is freed once the counter reaches 0 – the algorithms that decide when an object is “collected” are much more complex than what I’ve described but, for simplicity’s sake we’ll leave it like that – something that in other languages, like C++, is in the programmers hands.

So, can I forget about memory management ?! , I hear you ask in jubilation. The answer is yes and no; you see, for most tasks you won’t need to care about memory allocation and actually, I know programmers that have never had the need to know what volatile is. Now, some of you might remember an article published nearly 8 years ago, titled “The Free Lunch is Over” . In said article, the author commented on the fact that processor’s clocks weren’t getting any faster, whereas the number of cores they packed was increasing, therefore, any performance gains would not come simply as a result of a hardware upgrade any more, unless your software was designed to work with multiple cores. However, concurrent programing is not easy and it requires knowing very well what your memory is doing, as once you start sharing things among threads, things become very complicated very quickly,  this is, of course, if you don’t know what you’re doing. Sadly, I can’t claim – yet – that I know what I’m doing but, I intend to explore this concept further, in the context of the Java programming language and, publish my experiments here.

So I’m going to start now, with a simple question, what is the heap and what is the stack? . Surely, most programmers have heard of those two concepts but, let’s recap for a moment. All java programs run inside the JVM, and when the virtual machine is invoked to run your program, it will ask the hosting operating system some memory for running both itself and your program, that lump of memory is called The Heap*. So, when in your code you use the new  operator , to create an instance of one of your classes or an array or you declare a static variable, the JVM will allocate the memory needed for the object/array in the heap (note that the reference pointer to the object will be allocated in the stack); the heap itself is a bit more complicated than “a lump”, it’s actually subdivided further into 3 sections (‘Young Generation’, ‘Tenured Generation’ and ‘Permanent Generation’), this subdivision has to do with the way the garbage collector works and therefore, I will not talk about it now.

An OutOfMemoryError occurs when your program exhausts the maximum amount of memory allocatable by the JVM for the heap, see bellow for an in code example:

/**
 * Run this code with the following JVM options: -Xmx2m -Xms2m
 * This tells the JVM to allocate only 2Mb of heap space, for a maximum of 8Mb.
 * (that's in my 64bit linux desktop, it might vary in your system).
 */
public class Main {

    public static void main(String[] args) { 
            Set<String> collection = new HashSet<String>();
            while(true) {
                 collection.add(getReallyLongString(500));
            }
    }

    private static String getReallyLongString(int numberOfCharacters) {
        String longstring = new String();
        for(int i = 0; i < numberOfCharacters; i++) {
            longstring = longstring.concat("a");
        }
        return longstring + System.currentTimeMillis();
    }

}

If the heap is where your objects get allocated, what is The Stack then?. Well, not everything in your java application are objects, right?, what about primitive variables?, int, long, double, char, byte, boolean, they too need allocation. The primitive types don’t get allocated in the heap (unless they’re attributes of an object), they get allocated in the stack, however,  that’s not the only thing the stack is used for,  it also keeps track of method calls, stores method arguments, local variables and return values. So let’s say that you have 2 methods #myFirstMethod() and #mySecondMethod(), myFirstMethod calls mySecondMethod at some point during it’s execution. In terms of the JVM this means that when myFirstMethod is called, all it’s local primitive – non static – variables (this includes object references) will be neatly allocated and pushed into the stack, until the call to mySecondMethod is found, at that point, the local variables of mySecondMethod will be allocated and pushed into the stack, on top of the entry for myFirstMethod (it’s called stack for a reason), so when mySecondMethod finishes, it will be popped out of the stack then myFristMethod will be popped and so on and so forth until the call by the very first method is unrolled (this is always Main()  in case you hadn’t guessed it yet), and your program finishes.

A StackOverflowError happens when the stack’s space is exhausted. When the memory address for the stack is reserved, it’s done downwards, this means the address pool will go from say 0xFFFFFF to 0x000001, since every time you call a function, it’s address, parameters and local variables are stored in a new frame in the stack, recursive functions with the wrong termination condition,  are natural targets for this kind of error. If you run the code snippet below, you’ll get a StackOverflowError almost instantly.

public class Main {

    public static void main(String[] args) {        
            add(1);        
    }

    private static int add(int a) {
        return add(a + a);
    }
}

Now, here is an interesting question. When your program starts, the JVM creates a thread in which to run your Main() function, and so it creates a stack for that thread but, what if you started another thread within your Main() function?, well, as expected, the JVM would create another stack for that thread but, what if you wanted to use an object allocated in the first thread in this new thread?  and if the first thread, changed the object’s state while the second thread is running? what happens then?, that’s when things start to get tricky and, it will be the topic of posts to follow.

*Note: I’ve  also seen the heap being referred to as “main memory” in other articles.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: