Java Module 16
JVM internals, memory, GC and performance interview questions
Interview questions on JVM internals, memory, GC and performance: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher to mid
Java has a garbage collector. How can a Java program still leak memory?
Answered in the lesson Memory leaks, heap dumps and OOM errors
-
Fresher to mid
What is JDK Flight Recorder, and how do you start a recording?
-
Fresher to mid
Why is a loop around System.nanoTime() not a reliable benchmark of a Java method?
-
Fresher to mid
What is the AOT cache in JDK 25, and how do you create and use one?
-
Fresher to mid
How does a JDK 25 JVM choose its maximum heap inside a Linux container with a 2 GB memory limit and no heap flags?
-
Fresher to mid
What is the parent delegation model of Java class loaders, and why does it exist?
-
Fresher to mid
What do stack, locals and args_size mean in the output of javap -v?
-
Fresher to mid
What does "made not entrant" mean in the JIT's log, and should it worry you?
-
Fresher
Where do a method's local variables and the objects they refer to live in the JVM?
Answered in the lesson Heap, stack, references and object headers
-
Fresher to mid
What are the main garbage collectors in JDK 25, and when would you choose each?
Answered in the lesson Garbage collectors: G1, ZGC, Shenandoah
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Mid to senior
A payment service's heap after each full collection rises by about 40 MB a day, and the service fails with OutOfMemoryError about every nine days, so the team restarts it weekly. How would you find the leak in production without hurting latency, and how would you prove the fix?
- What it tests
- Telling a leak from a sizing problem, collecting low-overhead evidence in production, reading histograms and reference chains, and proving a fix with the same measurement.
- First step
- Confirm that it is a leak: take the heap occupancy after each collection from the GC log. A floor that climbs with traffic and never comes back down is a leak; a high but flat floor is a heap that is too small. Then plan two class histograms some hours apart, on an instance taken out of rotation.
- Follow-ups
-
- Histograms pause the JVM. How do you take them safely on a busy service?
- The class that grows most is byte[]. What next?
- How do you prove the fix before it reaches every instance?
From the lesson Memory leaks, heap dumps and OOM errors
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
An application server runs several web applications in one JVM. After about ten redeployments of one of them, the JVM fails with OutOfMemoryError: Metaspace. What is likely happening, how do you prove it, and what do you change?
- What it tests
- Class loader leaks, what keeps a class loader reachable, how Metaspace is limited, and the JDK commands that show class loaders and their classes.
- First step
- Count class loaders and loaded classes after each redeploy with jcmd <pid> VM.classloader_stats. If every redeploy adds a loader with the same few thousand classes and the old loaders never disappear, the old copies of the application are not being collected: something outside the application still references one of their classes.
- Follow-ups
-
- What typically keeps an old class loader alive?
- Why does raising MaxMetaspaceSize not help?
- How would you catch this kind of leak before production?
From the lesson Memory leaks, heap dumps and OOM errors
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A teammate wants to double -Xmx from 2 GB to 4 GB because the service fails with OutOfMemoryError: Java heap space every few hours. When is that the right fix, and what data would you ask for first?
- What it tests
- Distinguishing a leak from an undersized heap with data, what a bigger heap costs, and how a container's memory limit constrains the choice.
- First step
- Ask for the heap occupancy after each full collection over a day of traffic. If it climbs with the work done, a bigger heap only moves the failure: 4 GB fails after about twice the work. If it is flat but near 2 GB at peak, the live data needs more room, and a bigger heap is the fix.
- Follow-ups
-
- The service runs in a container with a 3 GB memory limit. What changes?
- Occupancy after collections is flat at 1.8 GB. How much heap would you give it?
- What would you watch after the change?
From the lesson Memory leaks, heap dumps and OOM errors
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A service's p99 latency doubled after last week's release, but its CPU usage looks normal. How would you use JDK Flight Recorder in production to see why, without restarting the service?
- What it tests
- Controlling JFR on a live JVM, choosing views for latency rather than CPU, and turning a recording into a testable cause.
- First step
- Normal CPU with worse latency points at waiting, not computing. Start a recording on one instance with jcmd <pid> JFR.start settings=profile, let it cover a few minutes of peak traffic, dump it, and look at the views for waiting first: lock contention, garbage collection pauses, file and socket reads, and thread states.
- Follow-ups
-
- Which views would you read first, and why those?
- The recording shows long pauses in the collector. What next?
- How do you confirm the cause before rolling anything back?
From the lesson JDK Flight Recorder and profiling
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A JFR profile put 70 % of its samples in one method, but making that method nearly instant made the job only 10 % faster. How can the profile and the stopwatch disagree, and how do you find what the profile missed?
- What it tests
- How sampling profilers work and fail, safepoint and native blind spots, allocation and waiting time, and checking a profile with measurements and arithmetic.
- First step
- Treat both numbers as evidence. Check how many samples the 70 % came from and whether the profile covered the same run and workload. Then look for time the execution samples cannot see: garbage collection, waiting on locks or input and output, native code, and work done on other threads.
- Follow-ups
-
- Why can a method be overweighted or underweighted by samples?
- Which other JFR data would you read, and what would each one show?
- How would you measure the remaining 90 % directly?
From the lesson JDK Flight Recorder and profiling
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
Support asks for a JFR recording from a customer's production system to investigate a slowdown. What can a recording reveal besides performance data, and how would you collect and share one safely?
- What it tests
- Knowing which JFR events describe the environment, the data-protection risk they carry, and practical ways to limit and handle that data.
- First step
- List what the default settings record beyond samples: the JVM's command line and system properties, the environment variables, the processes running on the machine, and file and network paths. Any of these can hold passwords, tokens or personal data, so decide what the investigation needs before anything is recorded.
- Follow-ups
-
- How do you keep sensitive events out of a recording?
- What does JDK 27 change?
- Who should be able to read the file, and for how long?
From the lesson JDK Flight Recorder and profiling
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A JMH benchmark of a JSON parser reports 0.4 ns per call, less than two clock cycles. What has probably happened, how do you prove it, and how do you fix the benchmark?
- What it tests
- Recognising dead-code elimination and constant folding, proving them with baselines and scaling, and the JMH idioms that prevent them.
- First step
- Compare the score with an empty benchmark in the same run. If they are about equal, the parser's work was deleted or precomputed. Then check whether the method returns or consumes the parsed result, and whether its input is a constant the compiler can see.
- Follow-ups
-
- What does a Blackhole do that a return value does not?
- How would you show that the work scales with the input?
- Why might the same benchmark be fine on another JVM or processor?
From the lesson Microbenchmarks with JMH
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A pull request claims a new lookup is 30 % faster, showing one JMH run of each version: 70 ± 25 ns against 100 ± 30 ns, on a laptop, with one fork. Would you accept the claim, and what would you ask for?
- What it tests
- Reading confidence intervals, the role of forks and environment, and how to design a fair comparison that a team can trust.
- First step
- Look at the intervals: 70 ± 25 spans 45 to 95 and 100 ± 30 spans 70 to 130, so they overlap and the data cannot support a 30 % claim yet. Ask for both versions in one JMH invocation, with several forks, on a quiet machine, with the environment stated.
- Follow-ups
-
- Why does running both versions in one invocation matter?
- How many forks and iterations would you ask for, and why?
- What other metric could settle it faster?
From the lesson Microbenchmarks with JMH
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
Your benchmark scores 12 µs in one fork and 19 µs in another, with tight errors inside each fork. What can cause this, and how should the result be reported?
- What it tests
- Run-to-run variance between JVMs, its typical causes, and honest reporting that includes the variance instead of hiding it.
- First step
- Treat the difference between forks as part of the result. Each fork is a new JVM that can make different JIT decisions, memory layouts and alignments, so look at the per-fork scores in the JSON output and run enough forks to see the distribution.
- Follow-ups
-
- Which JVM decisions can differ between forks?
- How would you investigate one bimodal benchmark?
- What would you put in the report?
From the lesson Microbenchmarks with JMH
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
Your team added an AOT cache to a service's container image, but production start-up did not improve at all. What would you check, and in what order?
- What it tests
- The conditions under which an AOT cache is used, reading the JVM's warnings, and building the cache so that it matches what production runs.
- First step
- First check whether the cache is used at all: start the container with -Xlog:aot=warning, or count where classes come from with -Xlog:class+load. A warning that the cache does not match means it is ignored, and every later check depends on that answer.
- Follow-ups
-
- The logs say the JAR's timestamp changed. How do you fix the build?
- The cache is used, but the gain is small. What next?
- How would you stop this from happening again unnoticed?
From the lesson Startup: AOT cache and native images
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A Java serverless function takes 1.8 s to start and 200 ms to handle a request. Compare an AOT cache and a GraalVM native image for it, and say what you would measure before deciding.
- What it tests
- Weighing start-up, warm-up, build cost and compatibility, and deciding from measurements of the real function rather than from general claims.
- First step
- Split the 1.8 s: JVM start, class loading, framework initialisation and the first, slow requests while the JIT compiler warms up. Then estimate how often cold starts happen, because a function that starts once an hour and one that starts on every request need different answers.
- Follow-ups
-
- What would make a native image impractical for this function?
- How would you measure both options fairly?
- When would you choose neither?
From the lesson Startup: AOT cache and native images
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
After a change to the build pipeline, a command-line tool shipped with an AOT cache starts more slowly than the same tool with no cache at all. Explain how that can happen, and how you would make the pipeline safe against it.
- What it tests
- What the JVM checks before using a cache, what it does on a mismatch, and building and verifying a cache in a pipeline.
- First step
- Check whether the JVM accepts the cache at all: run the shipped tool with -Xlog:aot=warning, and time it with and without the cache option on the same machine, several runs each. Then compare what the pipeline did before and after the change, step by step, up to the moment the cache was written.
- Follow-ups
-
- Why would a rebuilt JAR with identical classes not match?
- How can the pipeline fail fast instead of shipping a stale cache?
- What should production do if the cache does not match?
From the lesson Startup: AOT cache and native images
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A Java service in a container with a 1 GB limit is restarted several times a day with exit status 137, yet its GC logs show the heap never above 600 MB. What is happening, and how do you fix it?
- What it tests
- Telling a kernel kill from an OutOfMemoryError, accounting for memory outside the heap, and measuring it with Native Memory Tracking.
- First step
- Separate the two ways the service can run out of memory: an OutOfMemoryError thrown by the JVM, which its own logs would show, and the process being ended from outside. Then compare what the whole process uses, from the container's memory statistics, with what the heap uses, from the GC logs.
- Follow-ups
-
- Which parts of the JVM use memory outside the heap?
- How would you size the heap for this container?
- What if NMT's total is well below the container's usage?
From the lesson The JVM in containers and key flags
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
A service in a container limited to 1 CPU and 1 GB uses parallel streams and shows long garbage collection pauses on JDK 25. What did JVM ergonomics choose, and what would you change?
- What it tests
- How processor count and memory drive collector choice and thread pools, and how CPU quotas and JDK releases change them.
- First step
- Work out what the JVM saw: one processor and 1 GB, below the two processors and 1,792 MB of a server-class machine, so ergonomics chose the Serial collector. Confirm it with jcmd <pid> VM.flags, then check every thread count that depends on the processor count.
- Follow-ups
-
- Would two CPUs and the same memory change the collector?
- What happens with a limit of 1.5 CPUs?
- What changes in JDK 27?
From the lesson The JVM in containers and key flags
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
Review this start command for a web service in a container with a 2 GB memory limit and 2 CPUs: java -Xmx2g -Xss8m -XX:+UseParallelGC -jar app.jar. What is wrong, and what would you write instead?
- What it tests
- Budgeting heap against a container limit, the cost of thread stacks, and matching the collector to the workload.
- First step
- Check each flag against the 2 GB limit. A 2 GB heap leaves nothing for the memory the JVM needs outside the heap: class metadata, compiled code, thread stacks, the collector's own structures and buffers. Then ask what each of the other two flags is for, and what it costs.
- Follow-ups
-
- What does -Xss8m cost a service with 300 threads?
- When is the Parallel collector the right choice?
- How would you check the new flags under load?
From the lesson The JVM in containers and key flags
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
After a deploy, a service logs one ExceptionInInitializerError at start-up and then thousands of "NoClassDefFoundError: Could not initialize class com.shop.TaxTable", one per request. The class file is in the JAR. What is going on, how do you find the cause, and how do you make the next failure obvious?
- What it tests
- The initialisation procedure and the erroneous state, reading the first error rather than the echoes, and designing static initialisers and start-up checks that fail loudly.
- First step
- The class is present, so this is not a class path problem: "Could not initialize class" means the JVM already tried to initialise TaxTable and failed. Find the first ExceptionInInitializerError in the log, or the cause that JDK 25 attaches to each NoClassDefFoundError, and read its cause: that exception is the real bug.
- Follow-ups
-
- Why does every later request fail without running the initialiser again?
- How would you change TaxTable so that the failure stops the deploy instead?
- What changes if the class is loaded by a web application's own class loader?
From the lesson Class loading and JVM architecture
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A plugin host throws "ClassCastException: class com.acme.Rule cannot be cast to class com.acme.Rule (com.acme.Rule is in unnamed module of loader 'plugin-7'; com.acme.Rule is in unnamed module of loader 'app')". Explain how that is possible, how you confirm it, and how you fix and prevent it.
- What it tests
- Class identity as name plus defining loader, delegation between parent and child loaders, and designing the API boundary of a plugin system.
- First step
- Read the message literally: two classes with the same name, defined by two loaders. The plugin's loader defined its own copy of com.acme.Rule instead of delegating to the application loader, usually because the plugin's JAR bundles the API classes that the host also has. Confirm it with -Xlog:class+load, which prints every definition of the class with its source.
- Follow-ups
-
- Why did the plugin's loader define its own copy instead of using the host's?
- Which classes should a plugin loader take from its parent, and which from its own JAR?
- How can the same mistake leak memory after many plugin reloads?
From the lesson Class loading and JVM architecture
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A pull request replaces 400 anonymous listener classes with lambdas "to make start-up faster and the JAR smaller". What actually changes in the class files and at run time, and how would you check the claim with the JDK's own tools before agreeing?
- What it tests
- How javac compiles lambdas and anonymous classes, what invokedynamic linking costs at run time, and measuring start-up claims instead of guessing.
- First step
- Separate the two claims. The JAR does get smaller: each anonymous class is a class file of its own, while a lambda becomes an invokedynamic instruction and a private method. Start-up is a different question, because each lambda's class is still created at run time, the first time its invokedynamic runs. Count classes with -Xlog:class+load and time cold starts before and after.
- Follow-ups
-
- What does the first lambda in a program cost that later ones do not?
- How does capturing a variable differ between the two forms?
- Where would each version appear in a stack trace?
From the lesson Reading bytecode with javap
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A profile of a Java 25 service shows much time in StringBuilder.append inside a logging library that builds messages with +. The service's own code also uses + for strings and does not show up. Explain the difference and say what you would do.
- What it tests
- The two translations of string concatenation, why the class file's release decides which one runs, and choosing between rebuilding, upgrading and changing the logging calls.
- First step
- Run javap -c on the library's class and on one of your own. If the library was compiled for Java 8, its + is a chain of StringBuilder appends written into its bytecode, while your code, compiled for 25, has one invokedynamic to StringConcatFactory. Check the library's class-file version with javap -v: major version 52 means Java 8.
- Follow-ups
-
- Why does running the library on Java 25 not change its bytecode?
- Would the messages cost anything if the log level filters them out?
- What does javac's --release option change for this?
From the lesson Reading bytecode with javap
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
A code generator writes one method with a large try/finally block and about 60 return statements. The newest version fails with "code too large", and a smaller version that compiles runs far slower than hand-written code. Explain both from the bytecode and fix them.
- What it tests
- How javac compiles finally blocks, the JVM's limit on a method's code, and the JIT's refusal to compile very large methods.
- First step
- Look at the smaller version with javap -c -p and the exception table. Class files since Java 7 cannot use jsr and ret, so javac copies the finally code once for every way out of the try: 60 returns means about 60 copies. That growth explains the 65,535-byte limit being reached, and probably the slowness too.
- Follow-ups
-
- What limit does HotSpot's JIT put on the size of a method it compiles?
- How would you restructure the generated code?
- How can you confirm that the slow method was never compiled?
From the lesson Reading bytecode with javap
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
After every deploy, the p99 latency of a payment API is about five times higher for the first two minutes, then returns to normal. CPU is high during those minutes and nothing is wrong with the database. What is happening, and how do you shorten or hide it?
- What it tests
- JIT warm-up as a production concern, how to confirm it with the JVM's own logs, and the options from traffic shaping to warm-up requests and saved compilation work.
- First step
- Suspect warm-up first: a new JVM runs the hot paths in the interpreter and C1 while the compiler threads, which use CPU themselves, work towards C2 code. Confirm it by turning on -Xlog:jit+compilation or Flight Recorder on one new instance and checking that the latency falls as the hot methods reach tier 4.
- Follow-ups
-
- Why is CPU high exactly while latency is high?
- What makes warm-up requests safe to send to a payment service?
- How do the JDK's ahead-of-time cache features change the picture?
From the lesson JIT compilation and warm-up
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
A release added a third implementation of an interface that a hot loop calls, and throughput fell by a fifth, although the new class is used for only 2 % of calls. How do you show that the JIT is involved, and what are your options?
- What it tests
- Type profiles and call sites with one, two or more receiver classes, deoptimisation reasons in the JVM's logs, and weighing code changes against measured cost.
- First step
- Look for the call site in the JIT's own evidence before changing code: a Flight Recorder recording or -Xlog:deoptimization shows class_check and bimorphic_or_optimized_type_check events at the call's bytecode index in the hot method. With three receiver classes the call site can no longer be compiled for a short list of classes.
- Follow-ups
-
- Why does a class used for 2 % of calls affect the other 98 %?
- What would a microbenchmark of the loop with one, two and three classes show?
- Which code changes keep the hot call site to one or two classes?
From the lesson JIT compilation and warm-up
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
Each time a feature flag turns on a rarely used branch in a hot method, CPU jumps and latency spikes for about a minute. A Flight Recorder recording shows thousands of deoptimisation events with the reason unstable_if on that method. Explain what happens and propose fixes.
- What it tests
- Uncommon traps and how C2 compiles branches it has never seen taken, the cost of deoptimisation and recompilation, and code and rollout changes that avoid it.
- First step
- unstable_if means C2 compiled a branch that the profile showed as never taken as an uncommon trap. When the flag flips, every thread in that method hits the trap, falls back to the interpreter and waits for a new compilation, so a hot method briefly runs as slowly as cold code.
- Follow-ups
-
- Why are there thousands of events and not one?
- How would you roll out the flag to make the spike smaller?
- When is it worth restructuring the method?
From the lesson JIT compilation and warm-up
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
You must keep 50 million sensor samples in memory on JDK 25, each an int sensor id and a float reading. Estimate the heap for an array of records, two parallel arrays and an ArrayList of records, and say what compact object headers change.
- What it tests
- Estimating object sizes from headers, fields, padding and references, the cost of spare capacity in collections, and when compact headers pay.
- First step
- Size one record first: a 12-byte header, 4 bytes for the int and 4 for the float make 20, padded to 24 bytes. Then add what holds the records: an array of 50 million 4-byte references, or a list whose array has spare capacity. The parallel arrays need no headers per sample at all.
- Follow-ups
-
- What changes if the heap is set to 40 GB?
- Why can a list need 20 % more memory than its elements?
- How would you check your estimate on a running JVM?
From the lesson Heap, stack, references and object headers
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A team caches rendered product pages in a map of SoftReferences "so the JVM frees them when it needs memory". Under load the heap stays full, the service spends much of its time in garbage collection and latency spikes in waves. Explain and propose a better design.
- What it tests
- What soft references guarantee and what they leave to the collector, how a full soft cache interacts with collections, and designing a bounded cache with explicit eviction.
- First step
- Start from the guarantee: soft references must be cleared before an OutOfMemoryError, and otherwise the collector chooses when. A soft cache therefore grows until the heap is under pressure, so every collection runs with a full heap and then clears entries in bulk, which matches the waves.
- Follow-ups
-
- Why are the latency spikes periodic?
- What should decide which entries leave the cache?
- When is a SoftReference still the right tool?
From the lesson Heap, stack, references and object headers
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
A service releases native buffers through a Cleaner when their Java wrappers become unreachable. Its Java heap is stable, but the process's resident memory grows for days until the container is killed. What do you check, in what order, and how do you fix it?
- What it tests
- How Cleaner actions are triggered, the classic mistake that stops them, why heap metrics hide native memory, and making release explicit.
- First step
- The heap is stable, so look at what the heap does not show: native memory whose release depends on the collector. Check first whether the cleanups run at all, for example with a counter in the cleaning action, then read every registered action for a reference to its own object, such as a lambda that uses this.
- Follow-ups
-
- Why can the cleanups be late even when they are correct?
- Which JVM tool shows native memory by category?
- How should callers release the buffers instead?
From the lesson Heap, stack, references and object headers
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A latency-sensitive API runs on G1 with an 8 GB heap and shows p99 latency spikes of about 150 ms that line up with GC pauses in the log. Walk through how you would diagnose and fix it.
- What it tests
- Reading G1 logs to find which kind of pause is long, relating pause cost to live data, and choosing between heap sizing, G1 settings and another collector.
- First step
- First identify which pauses are long with -Xlog:gc: young, mixed, Remark or a Full GC. Each has a different cause. A Full GC means G1 ran out of space and fell back to a stop-the-world compaction; long young pauses usually mean much live data to copy or a young generation that is too large for the goal.
- Follow-ups
-
- What does a Pause Full line tell you, and what do you do about it?
- When would lowering MaxGCPauseMillis help, and when would it hurt?
- What would make you move this service to ZGC?
From the lesson Garbage collectors: G1, ZGC, Shenandoah
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A team moved a service to ZGC to cut GC pauses. Pause times dropped below a millisecond, but request latency got worse, and the log now has many "Allocation Stall" lines. Explain what is happening and how you would fix it.
- What it tests
- How a concurrent collector depends on heap headroom, why allocation stalls hide from pause metrics, and sizing a ZGC heap from the live set and the allocation rate.
- First step
- Read the stall lines as the real pauses: a thread that allocates while the heap is full waits until ZGC frees memory. ZGC's own pauses stay tiny, so the latency moved from pauses to stalls. The usual cause is a heap sized for a stop-the-world collector, with too little room above the live set.
- Follow-ups
-
- How much headroom does ZGC need, and how would you find out?
- Which metrics should the dashboards show after the change?
- What does SoftMaxHeapSize do, and when is it useful here?
From the lesson Garbage collectors: G1, ZGC, Shenandoah
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
One code base runs as a nightly batch job that must finish within an hour and as a public API with a p99 latency target of 50 ms. Both run G1 with default settings today. Would you give both the same collector settings? Defend a choice for each, and say what you would measure.
- What it tests
- Pause time and throughput as different goals, matching a collector to each workload, and proving a choice with measurements rather than habit.
- First step
- Write down what each workload is judged by. The batch is judged by its total run time, so the share of time spent in collection matters and single pauses do not; the API is judged by its slowest requests, so the longest pauses matter. Then measure both on today's settings with -Xlog:gc before changing anything.
- Follow-ups
-
- Why might Parallel finish the batch sooner than G1?
- What would make ZGC the right choice for the API?
- How would you roll out a collector change safely?
From the lesson Garbage collectors: G1, ZGC, Shenandoah
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes