Java Under the Hood — Part 2: Memory Management