JVM AND Core Java
Very Important INTERVIEW_QUESTIONS
JVM
The Java Virtual Machine (JVM) memory model is a crucial concept for understanding how Java applications run. It manages memory in several distinct regions, each serving a specific purpose. Here's an overview of the key memory areas: Heap , Stack , and Metaspace .
+------------------------------+
|
Method Area (
Metaspace
) |
+------------------------------+
|
Heap
|
+------------------------------+
|
Stack
|
+------------------------------+
|
Program Counter (
PC)
|
+------------------------------+
|
Native Method Stack
|
+------------------------------+JVM Memory Areas Recap:
| Area | Description |
|---|---|
| Heap | Stores objects and class instances. |
| Stack | Stores method frames, local variables. |
| Metaspace (Java 8+) | Stores class metadata, static methods, and constants. |
| Method Area (part of Metaspace ) | Stores class-level data like static variables, method info, and the string constant pool. |
JVM Memory Diagram (Java 8+)
+----------------------------------------------+
|
JVM Memory
|
+----------------------+-----------------------+
|
Heap
|
Metaspace
|
| (for
objects)
|
(
replaces
PermGen
)
|
|
|
|
|
+---------------+
|
+-----------------+
|
|
|
String
Objects|
|
|
String Constant
|
|
|
|
(e.g.,
new
|
|
|
Pool
|
|
|
|
String("a")) |
|
|
("a", "b",
etc
)
|
|
|
+---------------+
|
+-----------------+
|
|
|
|
|
|
+-----------------+
|
|
|
|
Static final
| |
|
|
|
constants
| |
|
|
|
(e.g. int MAX = 5| |
|
|
|
if
inlined
)
| |
|
|
+-----------------+
|
+----------------------+-----------------------+JVM Memory Diagram (Java 8+)
+---------------------------+
|
Java Thread
|
|
(
java.lang
.Thread
class) |
+---------------------------+
|
V
+---------------------------+
|
JVM Thread Structure
|
|
-
Java
Stack
|
|
-
Native
Stack
|
|
-
Program
Counter
|
|
-
Thread
ID
|
+---------------------------+
|
V
+---------------------------+
|
OS-Level Thread
|
|
(
pthread
/ Windows
API)
|
+---------------------------+Garbage Collection algorithms in Java
| GC Algorithm | Pause Time | Throughput | Heap Size Suitability | Multithreaded | Concurrency |
|---|---|---|---|---|---|
| Serial | High | Low | Small | ❌ No | ❌ No |
| Parallel | Medium | High | Medium to Large | ✅ Yes | ❌ No |
| CMS | Low | Medium | Medium | ✅ Yes | ✅ Partial |
| G1 | Low-Medium | High | Medium to Large | ✅ Yes | ✅ Partial |
| ZGC | Very Low | High | Huge (>1TB) | ✅ Yes | ✅ Full |
| Shenandoah | Very Low | High | Large | ✅ Yes | ✅ Full |
JVM options for GC logging:
-
Xlog:gc
*
-
XX:+
PrintGCDetails
-
XX:+
PrintGCDateStampsWhat are the best practices for designing immutable classes?
| Principle | Benefit |
|---|---|
| Final class | Prevents subclass modification |
| Private final fields | Prevents field mutation |
| Constructor initialization | Full object initialization |
| No setters | Ensures immutability |
| Defensive copies | Avoid shared mutable state |
| Immutable data structures | Safer multithreaded use |
How does synchronized, ReentrantLock , ExecutorService work?
| Feature | synchronized | ReentrantLock | ExecutorService |
|---|---|---|---|
| Locking Type | Intrinsic (object/class) | Explicit (manual control) | Task Execution & Thread Management |
| Unlock Requirement | Automatic | Manual ( unlock( )) | Not applicable |
| Fairness | No | Optional (new ReentrantLock (true)) | Depends on pool |
| Try Lock / Timeout | No | Yes ( tryLock ( ), tryLock (timeout)) | Not applicable |
| Interruptible | No | Yes | Yes (task cancellation APIs) |
| Use Case | Simple locking | Complex locking scenarios | Async task execution |
How is HashMap works internally/implemented
| Step | Description |
|---|---|
| 1️ ⃣ | When you put a key-value pair, the key’s hashCode ( ) is calculated. |
| 2️ ⃣ | That hashCode is used to compute the index (bucket) using index = hash % capacity. |
| 3️ ⃣ | If the bucket is empty, the new node is stored directly. |
| 4️ ⃣ | If the bucket already has a node, equals( ) is used to check for duplicates. |
| 5️ ⃣ | If equals( ) returns true, value is updated; otherwise, a new node is added to the chain (linked list or tree). |
| 6️ ⃣ | When a bucket’s chain becomes too long (threshold = 8), it's converted into a TreeNode (Red-Black Tree) for faster access. |
| 7️ ⃣ | When you call get(key), it computes the hashCode ( ) and index, then finds the node by checking keys with equals( ). |
| 8️ ⃣ | If key found ➝ returns value, else ➝ returns null. |
| 9️ ⃣ | HashMap resizes (doubles capacity) when the size exceeds threshold = capacity * loadFactor . Default load factor = 0.75. |
How is ConcurrentHashMap implemented?
ConcurrentHashMap is a thread-safe and highly concurrent implementation of a hash map in Java. It allows multiple threads to read and write without locking the entire map.
| Step | Description |
|---|---|
| 1️ ⃣ | ConcurrentHashMap uses segments internally in Java 7 , but buckets with Node arrays + CAS locking in Java 8+. |
| 2️ ⃣ | When inserting ( put( )), the key’s hashCode ( ) is computed to determine the bucket index. |
| 3️ ⃣ | If the bucket is empty , a new node is inserted using CAS (Compare-And-Swap) to ensure thread-safety. |
| 4️ ⃣ | If the bucket is not empty , threads use fine-grained locking only on that particular bucket/node. |
| 5️ ⃣ | If multiple threads try to write to the same bucket , only one thread locks that bucket — not the entire map. |
| 6️ ⃣ | If hash collisions occur, nodes are stored in a linked list , and converted to tree nodes (like HashMap) if they grow beyond threshold (8). |
| 7️ ⃣ | For reads ( get( )), it uses volatile reads , so it’s mostly lock-free — giving excellent performance. |
| 8️ ⃣ | Resizing is thread-safe and done using transfer bins where threads help in rehashing |
What is the difference between HashMap and ConcurrentHashMap ?
ü HashMap is not thread-safe and may produce inconsistent results in multithreaded environments.
ü ConcurrentHashMap allows concurrent access with thread safety using internal segment locking.
Thread Safety
A thread-safe class or method ensures that shared data is accessed and modified in a controlled and predictable manner . If two or more threads use it simultaneously, it will function correctly without needing additional synchronization from the user.
| Technique | Thread Safety | Use Case |
|---|---|---|
| synchronized | ✅ Yes | Simple critical section control |
| java.util .concurrent | ✅ Yes | Collections and utilities |
| Atomic variables | ✅ Yes | Lock-free counters, flags |
| Immutable objects | ✅ Yes | Data that never changes |
| Thread-local storage | ✅ Yes | Per-thread variable isolation |
| Locks ( ReentrantLock ) | ✅ Yes | Fine-grained locking, tryLock , fairness, etc. |
ReentrantLock implements Lock
ü It is the implementation class of Lock interface and direct child class of object.
ü Reentrant means a thread can acquire same lock multiple times without any issue.
How would you implement a thread-safe LRU cache?
Implementing a thread-safe LRU (Least Recently Used) cache in Java can be done in several ways. Here's a breakdown of the most common and effective approach using:
Approach: Use LinkedHashMap with synchronization
ü LinkedHashMap maintains insertion/access order.
ü Override removeEldestEntry to implement LRU eviction.
ü Add synchronization or use Collections.synchronizedMap () or ReentrantReadWriteLock for thread safety.
Parallel streams
It make use of the fork-join framework and its common pool of worker threads.
CompletableFuture
It is a class in Java ( java.util .concurrent ) that allows you to write asynchronous , non-blocking code. It helps you run tasks in the background and then continue processing once they’re complete.
Rich async composition, chaining, non-blocking where as feature java5 feature and it will perform Simple async task with blocking result
CompletableFuture is part of java.util .concurrent that represents a future result of an asynchronous computation.
| Step | What Happens |
|---|---|
| 1️ ⃣ | You call an async method like supplyAsync ( ) or runAsync ( ) to start work in the background. |
| 2️ ⃣ | Java spawns a new thread (from ForkJoinPool or custom executor). |
| 3️ ⃣ | When the task is done, CompletableFuture is completed with a result or an exception. |
| 4️ ⃣ | You can attach callbacks like . thenApply () , . thenAccept () , . thenRun () to chain further actions. |
| 5️ ⃣ | You can also combine multiple futures using . thenCombine () , . allOf () , . anyOf (), etc. |
| 6️ ⃣ | Finally, you can block using .get () (if needed) or handle exceptions using .exceptionally (). |
Explain memory leaks in Java. How do you detect and fix them?
ü Memory leaks happen when objects are no longer in use but are still referenced.
ü Tools: VisualVM , Eclipse MAT, JProfiler .
ü Common causes: static collections, listeners not removed, inner classes holding outer class references.
ü Fix: Ensure objects are dereferenced properly, use WeakReference when appropriate.
Bestways to use Concurrency in Java:
1. Use Modern Java Concurrency APIs (Avoid Thread and synchronized)
2. Prefer ForkJoinPool for Parallel Processing
3. Use CompletableFuture for Asynchronous Programming
4. Avoid Race Conditions with Atomic Variables or Locks
5. Avoid Deadlocks by Lock Ordering
6. Use ThreadLocal for Thread-Specific Data
7. Use ScheduledExecutorService for Periodic Tasks
8. Use Non-Blocking I/O (NIO) for High-Performance Applications
9. Prefer Virtual Threads (Java 21) Over Traditional Threads
10. Monitor and Tune Thread Performance