Caches that live in the heap
Integer.valueOf returns shared objects for -128 to 127 (the cache is required by the JLS for that range), so == happens to work there and fails above it. Always compare boxed values with equals.
A running JVM uses several separate memory areas: one shared heap for objects, one stack per thread for method frames, Metaspace for class metadata, a code cache for JIT-compiled code, and other native memory such as direct buffers and thread stacks. Each has its own limit, its own flag, and its own kind of OutOfMemoryError or StackOverflowError.
Change the code and press Run (Ctrl+Enter). Try to predict the output first, then break it on purpose and read the error. Your edits are saved and match the lesson page.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write a program that recurses until StackOverflowError, catches it, and prints whether a method with more local variables reached a smaller depth than one with fewer (print only the boolean).
Show that Integer.valueOf(100) returns the same object every time but new Integer(100)-style allocation (use Integer.valueOf on 1000) does not.
Write a program that creates a direct buffer, writes the ints 1 to 4 into it and reads them back, printing the sum.
Explain it without notes
Name the JVM's memory areas and what lives in each.
Your container keeps getting OOMKilled but the Java logs show no OutOfMemoryError. Why, and what do you do?
What changed when Metaspace replaced PermGen in Java 8?
Why does a HashMap<Integer, Integer> with a million entries use so much more memory than two int[] arrays of a million?
Expected output
127 == 127 (boxed): true
128 == 128 (boxed): false
128 equals 128: true
literal == folded literal: true
literal == runtime concat: false
literal == s3.intern(): true