Somehow, wherever I end up working in Seattle there are internal java projects fscking around with memory. At Haydrian I had a problem where a developer said that his code ran particularly slow on our company hardware compared to his, and therefore our hardware sucked and we were stupid. Basically anyways. The sarcasm helps the frustration.
It was java code, and I spent a bunch of time learning about how java “magically” handles memory for you. It’s great that developers don’t have to worry about memory anymore, i guess. Unfortunately the trade off is that they sometimes tend to use TONS of it, and then there are two solutions, 1) throw memory at their boxes (doesnt scale) or 2) learn whats going on and call them on it.
Being of the type that doesn’t like not knowing whats going on. I started learning about Garbage Collection. I’m still waking up this morning for some reason, so I’m writing this from memory rather than making a real stab at it because I should be doing other work, but I’m waiting for my concentration to improve. Besides, documentation should always be written when you’re not concentrating, that way you leave in little mistakes to totally confuse the reader.
That link goes to the big overview on the whole shebang. Basically java takes a bunch of memory, splits it up into different areas and moves data between these areas based on age, throwing it away if it’s not being used anymore. This is called, Garbage Collection. Exactly what methodology is used by default has changed over releases (too often). However, when GC runs aren’t getting enough memory back a “Full GC” is run, which most importantly stops code from running while it shifts the codes data around. If this doesn’t get enough memory, things blow up and java pukes altogether complaining about being out of heap.
Find your jvm installation ( /usr/local/java ?) and in the bin folder there a bunch of useful tools. I like ‘jps -l’ to list the jvms, which gives you their PID which is how you tell them apart. Then ‘jmap -heap PID’ will show you how the heap is split up. This is worth doing once just to see it, I think it makes more sense than a lot of the documentation out there and it’s definitely solidified what I’ve read over the last couple of years. There’s also, i think, ‘jstat -gccause’ which shows a vmstat like output of whats going on in the different areas (the man page should explain the columns) including what caused the last GC run, which keeping in mind can be hard coded in by the developer.
In testing, you can do things like adding “-verbose:GC” and “-XX:+PrintGCDetails” which makes java let you know (to stdout or stderr or whatnot) whenever a GC or Full GC is run and how long it took (this is important) and the latter adds more information such as what GC method was used, the memory in the different areas before and after the GC (so you can tell what area caused the GC run), etc.
When trying to fix problems, always start by paying attention to what -Xms and -Xmx are set to. These control the heap size by default and a lot of java programmers seemed to have learned that setting -Xmx as high as possible makes them not have to deal with this shit. -Xmx is the max heap size and -Xms is the starting heap size. Java controls the heap size as needed, but if you spend a lot of time tuning and know your code you can set these to the same thing.
It’s important to note that the Perm Gen or “Permanent Generation” is controlled separately. Normally you shouldn’t have to mess with this, as only classes and crap are stored here, but I’ve seen this be a problem recently. “-XX:PermSize=256m -XX:MaxPermSize=256m” would fix the PermGen at 256m. You can see the permgen in the aforementioned ‘jmap -heap PID’.
I guess that is about it. I haven’t really figured out debugging java beyond the GC, so I’ll leave that to you developers.