Java's Deep Copy Alternatives: Performance Comparative Analysis

Over the last few months, I have been thinking of building a sample project with the primary goal of comparing the performance of different techniques for creating deep copies in Java. The idea was to use the insights from this project and apply them in one of my real-world applications for performance enhancement.

You can find the source code of that sample project here.

The project tries to compare the performances of deep copying Java objects using serialization, reflection and copy constructor.

Disclaimer: It is essential to take into account the various factors. Serialization requires all classes to implement the java.io.Serializable interface. You need to handle the transient variables. If you are using a copy constructor, you need to give attention to multiple references to the same object and circular references. This article exclusively focuses on performance comparison, keeping the object hierarchy uncomplicated and direct.

Constructing a large object

Performance becomes crucial especially when dealing with the deep copying of sizeable Java objects.

In this context, the project generates a substantial object. Specifically, it constructs an instance of the Company class, encompassing 5 Department entities. Each Department entity further comprises 500 Employee instances, while each Employee object has 1 Address and is associated with 200 Task entities. The evaluation will reveal how effectively various copying methods can handle this sizeable data structure.

The size of the Company object encompassing all the child objects in the hierarchy is approximately 15.49 MB. This size was calculated using VisualVM by adding shallow sizes of all child objects as shown in the screenshot below:

Performance Comparative Analysis

I ran the tests on the Windows machine with an Intel(R) i7 1.70 GHz processor and 16 GB RAM.

The table below shows the average timings taken in milliseconds to deep copy the object using three different approaches. Even though the average timings for a technique vary across the number of iterations, the dissimilarities between the three techniques are pretty much the same.

Number of iterationsAvg. time using serializationAvg. time using reflectionAvg. time using the copy constructor
13869189554
53085177117
102968171620

It is quite obvious that deep copying with a copy constructor is blazingly fast, while serialization is the most expensive.

However, your choice of technique might depend on the size and complexity of the object structure, performance requirements, availability of time, maintenance overhead etc.

Feel free to use this source code to try out deep copying with your object hierarchies or with some other technique.