At Muvi, we always try to use best practices to ensure your app performs well across various devices. And memory optimization is a demanding task on that front.
Generally, while talking about memory optimization, most of us tend to think about the bigger sides. Due to this, we often miss the small things that can add up to a big problem. Autoboxing is one such topic that is often missed when talking about performance issues.
Autoboxing is often considered a great language feature. But as you keep using it, you start realizing its negative impact on your app’s performance. You cannot even imagine how much of your app’s memory is consumed by a simple Autoboxing operation.
So, in order to ensure optimized app performance, it’s really crucial to understand Autoboxing and find ways to avoid its negative impact. We have tried to do the same in this blog. Let’s dive in!
Autoboxing: What Is It?
In Java, autoboxing converts a primitive value into a wrapper class’s object. For example, an int data type can be converted to an integer.
Most of the time, autoboxing is an automatic conversion performed by the Java compiler if the primitive value is:
- Assigned to a variable of the respective wrapper class.
- Passed as an argument to a method that uses an object of the respective wrapper class.
For any version of JDK till JDK 1.4, it requires repetitive conversion of the primitive data types into wrapper classes and vice-versa.
Take, for example, you want to create a List with Integers. To do so, you will have to explicitly wrap them as Integer and then again unwrap them to get the int value. It can be troublesome and time-consuming.
To ease things out, conversion from primitive types to corresponding wrapper objects and vice versa is done automatically since JDK 1.5. The process is called Autoboxing and Unboxing, respectively. When building dynamic web applications with Java web development services, efficiency becomes paramount.
Autoboxing is the conversion of a primitive type to its corresponding reference type, as shown in the diagram below.
Unboxing
Unboxing is the reverse of autoboxing. If refers to the conversion of a wrapper type object to its respective primitive value. For example, an Integer object can be converted to an int data type via unboxing.
The Java compiler will perform unboxing when a wrapper class object is:
- Assigned a variable of the respective primitive type.
- Passed as an argument to a method that requires the corresponding primitive type’s value.
The process of unboxing is described in the diagram given below:
How Autoboxing Can Cause Problems?
As we saw above, during autoboxing, Java provides the corresponding wrapper classes that match the primitive types, and act as object wrappers. These classes perform the same functionalities as primitive data types but can be used with generic collections.
However, here’s the major catch – their size in memory is not the same! For example, an Integer object occupies 4 times more memory as a primitive int.
In the code example given below, the API call is adding a primitive int value but the collection API takes an Integer object. This assignment will perform an Autoboxing operation from int to Integer object.
Here only a single call is taking place. So, in this case, it may not matter much.
But, if you are using similar operations frequently, for example in an inner loop, it will occupy a lot of unnecessary memory. Then, it will cause a big memory threat.
As you can see in the code snippet above, 100 new objects were allocated and the sum was calculated here.
However, if we had used primitive data types, it would not require any additional allocation overhead. The process used here will lead to more garbage collection and decrease the runtime performance. It can be especially painful with data structures like HashMap.
Now let’s examine another code snippet:
In the above code, put and get operations will use autoboxing and unboxing, causing additional load. Basically, anytime you insert, update, or retrieve a value with this generic container, you will end up boxing or unboxing values whenever a primitive is involved.
The Effective Solution
In order to solve this issue of Autoboxing, Android has provided custom containers SparseArrays and ArrayMap. These containers can be used instead of traditional containers like HashMap.
These special containers are designed specifically to fight the Autoboxing problem. They eliminate both runtime overhead and additional memory allocation. These containers are more memory efficient than using a HashMap to map Integers to Objects.
In this way, you can make your code more optimized and memory efficient.
To understand SparseArray and ArrayMap refer to these detailed posts:
- App optimization with ArrayMap
- SparseArray in Android
How to Trace Memory Issues?
Android Studio offers multiple profiling tools. You can use these tools to record and compute the memory allocations of your app.
Allocation Tracker is one tool. It is quite a powerful profiling tool that shows object allocation and their size, along with memory leaks.
Click here to learn more about inspecting your app’s memory usage with Memory Profiler
Conclusion
Nowadays, most of the applications are handling enormous amounts of data. So, these optimizations could potentially improve the performance across applications.
This small change of autoboxing matters a lot for a mobile developer, especially when you have very limited memory and resources.
Add your comment