01
JVM Internals
A class passing through the class loader hierarchy into its runtime, and which thread runs its initialization; the memory areas that decide whether a value is thread-local or shared; who takes on the cleanup of an object that has lost its reachability; and which data, and on which side, gives rise to an optimization decision not found in the class file.
- 01 Class Loading The class loader hierarchy runs on delegation: the class a loader is asked for is, in most cases, defined by the loader above it, and identity is read only through `==`. Three of four triggers run class initialization; one — reading a compile-time constant — never does. When two threads touch the same class at the same time, only one of them runs the initialization block; the other waits for it to finish.
- 02 Memory Areas Three of six values written by the same thread are never visible to another thread, and three are — what decides this is not the value's type but where it sits: a local variable and a parameter sit in the call frame, an object field and an array element sit on the heap, a static field sits in the class's own storage. Being shared is not being visible: without an ordering tool, the same read is undefined.
- 03 Garbage Collectors Who takes on the cleanup of an object that has lost its reachability: not the caller, not a thread the program created — a party that never appears in any record at all. Cleanup does not run while a strong reference stands and runs once it is removed; a weak and a phantom reference get enqueued within a few requests; a soft reference resists as long as there is no memory pressure. `System.gc()` is a request, not a command.
- 04 Just-in-Time Compilation The class file holds no optimization decision at all: even if the same method is called three hundred thousand times, the instruction list read from the class file stays byte-for-byte identical. The party that makes the decision is not the program itself; the receiver type count the decision rests on, though, is produced by the calling thread while it runs. When a call site moves from monomorphic to polymorphic, the assumption becomes invalid — this lesson does not measure speed, it only counts instructions and receiver types.