Demonstrating Deep vs Shallow Copy in Java Using Heap Dumps
This article explains how to avoid thread‑unsafe statistics collection by copying objects per thread, explores Java deep and shallow copying concepts, provides a concrete test program, and uses JConsole and heap dumps to verify the number of object instances created by each copying method.
When rewriting a performance‑testing framework, the author encountered a thread‑safety issue: each thread needed its own statistics object, and sharing a single instance caused unsafe behavior. To keep threads independent without locking, the solution was to clone the object for each thread.
While investigating, the author revisited Java deep and shallow copy principles and decided to demonstrate the differences using memory analysis. Three copying approaches are described: assigning the reference directly (a1 = a), performing a shallow copy (a2), and performing a deep copy (a3). The expectation is that the shallow copy shares nested objects, while the deep copy creates separate nested instances.
The following Java program implements the test. It creates a Tttt object that contains a nested Sss object, then performs three actions: a pause, a heap dump, a shallow clone via clone() , another pause and heap dump, and finally a deep clone using a custom deepClone method, followed by a third heap dump.
package com.fun;
import com.fun.frame.SourceCode;
import java.io.Serializable;
public class AR extends SourceCode {
public static void main(String[] args) {
waitForKey("1");
HeapDumper.dumpHeap("1",true);
Tttt clone = tttt.clone();
waitForKey("2");
HeapDumper.dumpHeap("2",true);
Tttt tttt1 = deepClone(tttt);
HeapDumper.dumpHeap("3",true);
waitForKey("3");
}
static class Tttt implements Cloneable, Serializable {
public Sss sss = new Sss();
private static final long serialVersionUID = 4989553780571753462L;
public Tttt clone() {
try {
return (Tttt) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
static class Sss implements Cloneable, Serializable {
private static final long serialVersionUID = -5487147719650620894L;
public Sss clone() {
try {
return (Sss) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
}Using three pauses, the author generated three heap dump files and inspected them with JConsole’s MBean tool. The dumps were then served via jhat -port 8001 1 and viewed in a browser at http://localhost:8001/ . By navigating to the instance view for the Tttt and Sss classes, the number of live instances could be observed.
The inspection showed exactly the expected counts: one, two, and three Tttt instances (corresponding to direct reference, shallow clone, and deep clone) and one, one, and two Sss instances (since the shallow copy shares the nested object while the deep copy creates a new one).
Thus, the experiment confirms the theoretical differences between reference assignment, shallow copy, and deep copy in Java, and demonstrates how heap dumps can be used to verify object allocation behavior.
FunTester
10k followers, 1k articles | completely useless
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.