HeapHero is a world-class heap dump analysis tool. On top of doing traditional heap dump analysis, it’s the first tool in the industry to report the wasted memory.
Table of Contents
- Introduction
- Heap Statistics
- Whats in your Memory
- Large Objects
- Thread Report
- Object Headers
- Duplicate Strings
- Duplicate Objects
- Duplicate Primitive Arrays
- Inefficient Collections
- Inefficient Object Arrays
- Inefficient Primitive Arrays
- Boxed Numbers
- Objects Waiting for Finalization
- Heap Settings Recommendation
- System Properties
- Report Sharing
1. Introduction
HeapHero is a world-class heap dump analysis tool. On top of doing traditional heap dump analysis, it’s the first tool in the industry to report the wasted memory. Industry has produced several tools to measure the memory consumption. But there is no tool to report, how much memory is used for real work and how much is wasted. Modern applications waste memory because of several reasons: Duplicate String, Duplicate Objects, Inefficient Collections,… HeapHero detects those inefficiencies, their origination points in the source code and provides solutions to fix them.2. Heap Statistics
Fig 2.1: Heap Statistics
This section of the report provides key metrics of your application’s memory utilization.
- Total Size: Cumulative size of all objects that are present in the memory when heap dump was captured. In the example given above, application has 419.96mb of objects.
- Object Count: Total number of objects that were present in the memory when heap dump was captured. In the example given above, application has 8 million+ objects (i.e. 8,083,402).
- Class Count: Total number of classes that were present in the memory when heap dump was captured. In the example given above, application has 33,406 classes.
- Thread Count: Total number of threads that were present in the application when heap dump was captured. In the example given above, application has 178 threads.
- Memory Wasted: Due to inefficient programming practices, lot of memory is wasted. This section reports the amount of memory wasted by your application. In the example given above, application is wasting 172.23mb of memory i.e. 41% of total memory. This section also displays a pie graph, which shows the breakdown of where memory is getting wasted. Apparently, this application is wasting memory in the following forms:
- Duplicate Strings: 86.38mb (20.6%)
- Inefficient Primitive Arrays: 24.5mb (5.8%)
- Inefficient Collections: 24.08mb (5.7%)
- Duplicate Primitive Arrays: 17.89mb (4.3%)
- Inefficient Object Arrays: 12.44mb (3.0%)
- Boxed Numbers: 6.39mb (1.7%)
- Objects waiting for finalization: 48b (< 0.1%)
There are various sections in the report, which shines more details of each of the problem. You can go to the appropriate sections to learn more about the wasted memory.
3. What’s in your Memory (by class)?
Fig 3.1: Classes occupying substantial portion of memory
This section of the report shows the histogram of the classes that occupy substantial portion of memory. They are sorted by their size and presented in this section.
Apparently in the given example, ‘java.lang.String’ class occupies maximum amount of memory in this application. It occupies 149.76 mb i.e. 35.7% (which is significant amount). Totally there are 1.7 million+ (i.e. 1,757,583) instances of String objects in the memory.
Fig 3.2: Showing all the objects that are referencing the class
When you click on the name of the class, it will show all the objects that are referencing this class. In this example, it shows the top objects that are referencing ‘java.lang.String’ class. This gives clear visibility into the application code, on who is holding on to substantial portion of String objects.
4. Large Objects
Fig 4.1: Large Objects in the memory
This section of the report shows the large objects that are residing in the memory. Typically memory leaking objects tend to be large in size. Thus if your application is suffering from memory leak, this is the section that you need to focus.
This section shows the largest objects and size they occupy in memory. In the above example ‘org.apache.axis.utils.Messages.classLoader’ occupies 76.59mb of memory i.e. 18.2% of overall memory. It’s a “static” field. When you click on the name of the object, it will show the object tree of that object.
Fig 4.2: Large Object Tree
Object Tree shows all the objects, it’s children, grandchildren, great-grandchildren,… that are referenced by it. This object tree will give you the clear visualization of code path is causing the memory leak.
5. Thread Report
Thread Report gives a detailed overview of the threads running in the application. This thread report is generated by our sister product fastThread.io
6. Object Headers
When you create objects, JVM creates Object Headers to manage them. This Object Header contains metadata about the object itself like (Class information, Hash code, Synchronization lock, …). Object Headers size will vary anywhere from 8 to 16 bytes based on the version (32-bit or 64-bit), mode (‘narrow pointer’ or ‘wide pointer’), etc. If it turns out to be an array, additional 4 bytes is added to object header to keep track of its size. Thus, if your application ends up creating lots of small objects, then object headers itself can add considerable overhead to the application.
HeapHero detects the amount of memory overhead due to the object headers. This information is reported under the “Object Headers” section of the report. Let’s review the details of this section.
Object Headers statistics
Fig 6.1: Important statistics about object headers
HeapHero reports following important statistics about object headers:
- Object Header Size: This is the average size of an object header in the application. As per the above example, this application’s header size is 12 bytes.
- Total size of all headers: This is the cumulative size of all object headers in the application. As per the above example, total size of all object headers in the application is 92.51mb i.e. 22.0%. It’s a significant overhead.
Top Object Headers statistics
Fig 6.2: Top object headers present in the application
This section shows the top object headers that are present in the application. According to the example given in Fig 6.2, “char[]” adds maximum object header overhead. This application has 1,764,204 instances of “char[]”. While the average size of “char[]” is only 70, the total header size of “char[]” sums up to 20.19mb i.e. 4.8% of overall memory.
How to fix object headers overhead?
This section of HeapHero provides recommendations to fix the object headers overhead in your application. However, it’s available only in Enterprise Edition.
7. Duplicate Strings
Most modern applications waste at least 10% of memory, due to string duplication. What do we mean by String duplication? i.e. multiple instances of same string objects exist in the memory. Modern applications do a lot of string manipulations due to Webservice API calls (i.e. JSON, REST, SOAP, …), external data sources calls (SQLs, data returned back from DB, …), text parsing, text building,. Thus poor programming practice can lead to generation of tones of duplicate strings in the application memory.
HeapHero detects the amount of memory wasted due to duplicate strings in your application and reports them under the “Duplicate Strings” section of the report. Let’s review the details of this section.
Duplicate Strings Statistics
Fig 7.1: Important statistics about duplicate strings
HeapHero reports 3 important statistics about duplicate strings:
- Total Strings: Total number of string objects present in your application.
- Unique Strings: Number of unique strings present in the application. As per the above example, there are 1,758,461 total strings present in the application. Out of it, 540,519 strings are unique. Remaining 1,217,942 (i.e.1,758,461 – 540,519 ) strings are duplicates.
- Wasted Memory: This is the amount of memory wasted due to duplicate strings in your application. In this example, it’s 79.48 MB i.e. 11.2%. If you are going to eliminate all the duplicate strings in your application, you can save 79.48mb of memory.
Top Duplicate Strings
Fig 7.2: Top duplicate strings present in the application
This section shows the top duplicate strings that are present in the application. According to the example given in Fig 7.2, there are 95,041 instances of “wsam” string objects. These many duplicate strings occupy 4.35mb i.e. 0.6% of overall memory. In other words, if you can eliminate all the duplicate instances of “wsam” string, you will be able to reduce the memory size by 4.35mb.
Who is holding Duplicate Strings?
Fig 7.3: What Objects are holding on to duplicate strings
This section of the report shows the large objects that are holding on to duplicate strings in the application. According to the example given in Fig 7.3, “{java.util.HashMap}.values” object holds a lot of duplicate strings. This object’s overall size is 4,390KB and it occupies 0.6% of memory. You can click on the first column (i.e. “{java.util.HashMap}.values”), to see the complete object tree as shown in Fig 7.4.
Fig 7.4: Object Tree
This section of the report shows the object tree of “{java.util.HashMap}.values” i.e. basically parent, grandparent, great-grandparent,… of “{java.util.HashMap}.values”. This tree will help you identify the part of your source code that is originating this memory overhead.
This section also shows the top duplicate strings held by “{java.util.HashMap}.values”. Apparently, in this case, there are 25868 instances of string value “2”, 24896 instances of string value “1”,…
How to fix Duplicate Strings?
This section of HeapHero provides recommendations to fix Duplicate Strings in your application. However, it’s available only in Enterprise Edition.
8. Duplicate Objects
HeapHero detects duplicate objects in your application. Duplicate objects waste memory. If there is no valid reason to keep duplicate objects, you may consider eliminating them. This pattern detection is very similar to duplicate strings. Let’s review the details of this section.
Duplicate Objects Statistics
Fig 8.1: Important statistics about duplicate objects
HeapHero reports 2 important statistics about duplicate objects:
- Total Duplicate Objects: The total number of duplicate objects present in your application.
- Wasted memory: This is the amount of memory wasted due to duplicate objects in your application. In this example, it’s 1.97 MB i.e. 1.3%. If you are going to eliminate all duplicate objects in your application, you can save 1.97 MB of memory.
Types of Duplicate Objects
Fig 8.2: Types of duplicate objects present in the application
This section shows the type of duplicate objects that present in your application. According to the example given in Fig 8.2, there are 14,537 objects of type “java.lang.reflect.Method”. This type of duplicate objects occupies 1.11 MB i.e. 0.7% of memory.
Top Duplicate Objects
Fig 8.3: Top duplicate objects present in the application
This section shows top duplicate objects that present in the application. According to the example given in Fig 8.3, there are 4890 instances of “j.l.r.WeakReference(referent: class java.lang.String, queue: j.l.r.ReferenceQueue$Null@660d17bb8, next: null, discovered: null)”. These many duplicate objects occupy 152.78 kb i.e. < 0.1% of overall memory. If you can eliminate all duplicate objects, you will be able to reduce the memory size by 152.78 kb.
Who is holding Duplicate Objects?
Fig 8.4: What objects are holding on to duplicate objects
This section of the report shows the large objects that are holding on to duplicate objects in the application. According to the example given in Fig 8.4, “{j.u.HashMap}.values” object’s overall size is 297 kb and it occupies 0.2% of memory. You can click on this object to see the complete object tree as shown in Fig 8.5.
Fig 8.5: Object tree
This section of the report shows the object tree of “{j.u.HashMap}.values”. This tree will help you identify the part of your source code that originates this memory overhead.
This section also shows top duplicate objects held by “{j.u.HashMap}.values”. There are 176 objects of “java.lang.reflect.Method(override : false, securityCheckCache : null, clazz: class …”
How to fix Duplicate Objects?
This section of HeapHero provides recommendations to fix Duplicate Objects in your application. However, it’s available only in Enterprise Edition.
9. Duplicate Primitive Arrays
HeapHero detects duplicate primitive arrays in your application. Duplication wastes memory. If there is no valid reason to keep duplicate primitive arrays, you may consider eliminating them. This pattern detection is very similar to duplicate strings. Let’s review the details of this section.
Duplicate Primitive Arrays Statistics
Fig 9.1: Important statistics about duplicate primitive arrays
HeapHero reports 2 important statistics about duplicate primitive arrays.
- Total Duplicate Arrays: The total duplicate arrays present in your application.
- Wasted Memory: This is the amount of memory wasted due to duplicate primitive arrays in your application. In this example, it’s 17.89 MB i.e. 4.3%. If you are going to eliminate all duplicate primitive arrays in your application, you can save 17.89 MB of memory.
Types of Duplicate Primitive Arrays
Fig 9.2: Types of duplicate primitive arrays present in the application
This section of Heaphero report shows types of duplicate primitive arrays present in your application. According to the example given in Fig 9.2, there are 10,983 duplicate primitive arrays of type “byte[]”. This type of duplicate primitive arrays occupies 7.83 MB i.e. 1.9% of overall memory. If you eliminate these duplicate primitive arrays, you will be able to reduce the memory size by 7.83 MB.
Top Duplicate Primitive Arrays
Fig 9.3: Top duplicate primitive arrays present in the application
This section shows the top duplicate arrays present in your application. According to the example given in Fig 9.3, there are 484 duplicate arrays of “byte[8000](0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,…)”. These many duplicate primitive arrays occupy 3.69 MB i.e. 0.9% of memory.
Who is holding Duplicate Primitive Arrays?
Fig 9.4: What objects are holding on to duplicate primitive arrays
This section shows the large objects holding duplicate primitive arrays in the application. According to the example given in Fig 9.4, “java.nio.HeapByteBuffer.hb” object holds duplicate primitive arrays. This object’s overall size is 1,718 kb i.e. 0.4% of memory. You can click on this object to see complete object tree as shown in Fig 9.5.
Fig 9.5: Object tree
This section of the report shows the object tree of “java.nio.HeapByteBuffer.hb” i.e. basically parent, grandparent, great-grandparent,… of “java.nio.HeapByteBuffer.hb”. This tree will help you to identify the part of your source code that is originating this memory overhead.
This section also shows top duplicate primitive array held by “java.nio.HeapByteBuffer.hb”. Apparently in this case there are 224 instances of primitive arrays “byte[8000](0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,…)”.
How to fix Duplicate Primitive Arrays?
This section of HeapHero provides recommendations to fix the Duplicate Primitive Arrays in your application. However, it’s available only in Enterprise Edition.
10. Inefficient Collections
Collections (i.e. ArrayList, HashMap, Hashtable,…) provides powerful APIs for application development. However, inefficient Collection implementations can add significant memory overhead to the application. There are four types of collections inefficiencies:
- Collections which has 0 elements
- Collections which has just 1 element
- Collections which has 2 – 4 elements only
- Collections that have more than half ‘null’
Let’s study these inefficiencies in detail.
1. Collections which has 0 elements
Sometimes, Collections objects are created and they don’t contain any elements in it. You might wonder why one would create Collections object and not add any element to it. But based on our experience, we are seeing this pattern a lot in major enterprise applications.
When you create a new ArrayList object, by default it creates 10 elements. When you create a new HashMap object, it creates 16 elements. Depending on the type of Collections object you create, it occupies anywhere from 100 bytes (ArrayList) to 1000 bytes (ConcurrentHashMap). These memory gets wasted if no objects are inserted into them.
2. Collections which has just 1 element
Sometimes collections objects are created, and they just end-up having 1 element in them. Collections add a lot of overhead for the functionality it provides. It’s necessary to create Collections only if it’s going to manage several elements.
3. Collections which has 2 – 4 elements only
Sometimes collections objects are created and they just end-up having 2 – 4 elements in them. Collections add overhead for the functionality it provides. It’s necessary to create Collections only if you are going to manage several elements. A HashMap with less number of elements will have poor performance than a plain array.
4. Collections that have more than half ‘null’
There are collections which have more than 4 elements, but more than half the size of elements is with null values. This problem can happen because of following reasons:
- High initial capacity: When Collections are created with very high initial capacity, but very fewer elements are added to it.
- Shrinking: Elements can be removed from the Collection after they are added. Most collections are implemented with underlying plain arrays. But as you all know arrays won’t shrink once they are created. They will tend to have null values.
- Expansion: Suppose, current capacity of the Collection object is 80 and there are 75 elements in it. Let’s say you want to add additional more 6 elements to the collection. In this scenario, there is only room to add 5 more elements. So, most collections double its size to accommodate new elements. As per this example, size of the collection will become 160. (Because of current capacity 80 * 2). But the actual number of elements will be only 81 (i.e. 75 old elements + 6 new elements). Thus remaining 79 (i.e. new capacity – current size i.e. 160 – 81) elements will tend to have null values. This might be fine when there are only limited elements. But assume if there are thousands/millions of elements in the collection; the significant amount of memory will be wasted.
HeapHero detects the amount of memory wasted due to inefficient collections in your application and reports them under the “Inefficient Collections” section of the report. Let’s review the details of this section.
Inefficient Collections Statistics
Fig 10.1: Important statistics about inefficient collections
HeapHero reports 3 important statistics about inefficient collections:
- Total Collection: Total number of collections present in your application.
- Inefficient Collections: Number of inefficient collections present in your application. As per the above example, there are 138,878 total collections present in your application. Out of it, 123,999 collections are inefficient.
- Wasted Memory: This is the amount of memory wasted due to inefficient collections in your application. In this example, it’s 18.04 MB i.e. 11.5% of overall memory. If we are going to remove all the inefficient collections in the application, we can save 18.04 MB of memory.
Top Inefficient Collections
Fig 10.2: Top inefficient collections present in the application
This section shows top inefficient collections that present in the application. According to the example given in Fig 10.2, 34% of “j.u.HashMap” in the application contains no element. These type of elements occupy 4.62 MB i.e. 3.0% of memory.
Who is holding Inefficient Collections?
Fig 10.3: What objects are holding on to inefficient collections
This section of the report shows the large objects that are holding on to inefficient collections in the application. According to the example given in Fig 10.3, “org.apache.catalina.startup.ContextConfig.javaClassCache” this object’s overall size is 2,048 kb and it occupies 1.3% of memory. You can click on this object to see the complete object tree as shown in Fig 10.4.
Fig 10.4: Object tree
This section of report shows object tree of “org.apache.catalina.startup.ContextConfig.javaClassCache” i.e. basically parent, grandparent, great-grandparent,… of “org.apache.catalina.startup.ContextConfig.javaClassCache”. This tree will help you identify the part of your source code that originates this memory overhead.
How to fix Inefficient Collections?
This section of HeapHero provides recommendations to fix the inefficient collections in your application. However, it’s available only in Enterprise Edition.
11. Inefficient Object Arrays
Inefficient Object array implementations can add considerable memory overhead to the application. There are 5 types of inefficient object array implementations:
- Arrays with all ‘null’ elements
- Arrays with 70% or more ‘null’ elements
- Arrays with Length 0
- Arrays with Length 1
- Single-element arrays
Let’s study these inefficiencies in detail.
1. Arrays with all ‘null’ elements
Some object arrays in memory tend to have ‘null’ values in all its elements. There is a wrong notion that ‘null’ values in each array element don’t waste memory. This is a myth. They do waste memory. In this case, entire object array + object header of that array ends up wasting the memory.
2. Arrays with 70% or more ‘null’ elements
Sometimes object arrays end up having 70% or more elements with ‘null’ values. This may not be a problem when array size is small. On the other hand, if array size tends to be very large or there are multiple object arrays with 70% or more null elements, it will add considerable overhead to your application’s memory.
3. Arrays with Length 0
Some object arrays are initialized with length 0. Example:
String[] myStrings = new String[0];
When you initialize Object Arrays with length 0, no elements can be added to the array. Entire Array will just become useless. You might wonder who will initialize object arrays with 0 length? But based on our heap dump analysis, we have seen this problem multiple times when analyzing multiple heap dumps.
4. Arrays with Length 1
Sometimes object arrays are initialized with length 1. Example:
String[] myStrings = new String[1];
If object arrays are initialized with length 1, then only one element can be inserted into the array. In such circumstance, you don’t need an overhead of an entire array.
5. Single-element arrays
This problem is very similar to ‘Arrays with Length 1’, but with a minor difference. In ‘Arrays with Length 1’ problem, length of object array is 1 and there is only 1 element in the array, whereas in this pattern, length of object array can be more than 1, but it has only 1 valid element. Remaining elements of the array will have ‘null’ values.
Inefficient Object Arrays Statistics
Fig 11.1: Important statistics about inefficient object arrays present in the application
HeapHero reports 3 important statistics about inefficient object arrays:
- Total Object Arrays: The total number of object arrays present in the application.
- Inefficient Object Array: Number of inefficient object arrays present in the application. As per the above example, there are 603,138 total object arrays present in the application. Out of it, 317,775 object arrays are inefficient.
- Wasted Memory: This amount of memory wasted due to inefficient object arrays in the application. In this example, it’s 12.44 MB i.e. 3.0% of overall memory. If we are going to remove all inefficient object arrays, we can save 12.44 MB of memory.
Top Inefficient Object Arrays
Fig 11.2: Top inefficient object arrays present in the application
This section shows top inefficient object arrays present in the application. According to the example given in Fig 11.2, 5% of “object[]” in the application contains no elements. These type of elements occupy 3.02 MB i.e. 0.7% of memory.
Who is holding Inefficient Object Arrays?
Fig 11.3: What Objects are holding on to inefficient object arrays
This section of the report shows large objects that are holding on to inefficient object arrays in the application. According to the example given in Fig 11.3, the overall size of the object “io.netty.util.internal.MpscArrayQueue.buffer” is 1,812 kb and it occupies 0.4% of memory. You can click on this object to see the complete object tree as shown in Fig 11.4.
Fig 11.4: Object tree
This section of the report shows object tree of “io.netty.util.internal.MpscArrayQueue.buffer” i.e. basically parent, grandparent, great-grandparent,… of “io.netty.util.internal.MpscArrayQueue.buffer”. This tree will help you identify the part of your source code that originates this memory overhead.
How to fix Inefficient Object Arrays?
This section of HeapHero provides recommendations to fix the inefficient object arrays in your application. However, it’s available only in Enterprise Edition.
12. Inefficient Primitive Arrays
Inefficient primitive array implementations can add considerable memory overhead to the application. There are 5 types of inefficient primitive array implementations:
- Arrays with all ‘0’ values
- Arrays with 25% or more ‘0’ values
- Arrays with Length 0
- Arrays with Length 1
- Single-element arrays
Let’s study these inefficiencies in detail.
1. Arrays with all ‘0’
Some primitive arrays in memory tend to have ‘0’ value in all its elements. There is a wrong notion that ‘0’ value in each array element doesn’t waste memory. This is a myth. They do waste memory. In this case, entire primitive array + object header of that array ends up wasting the memory.
2. Arrays with 25% or more ‘0’ values
Sometimes primitive arrays end up having 25% or more elements with ‘0’ values. This may not be a problem when array size is small. On the other hand, if array size tends to be very large or there are multiple primitive arrays with 25% or more ‘0’ values, it will add considerable overhead to your application’s memory.
3. Arrays with Length 0
Some primitive arrays are initialized with length 0. Example:
int[] myInts = new int[0];
When you initialize primitive arrays with length 0, no elements can be added to the array. Entire Array will just become useless. You might wonder who will initialize primitive arrays with 0 length? But based on our heap dump analysis, we have seen this problem multiple times when analyzing multiple heap dumps.
4. Arrays with Length 1
Sometimes primitive arrays are initialized with length 1. Example:
int[] myInts = new int[1];
If primitive arrays are initialized with length 1, then only one element can be inserted into the array. In such circumstance, you don’t need an overhead of an entire array.
5. Single-element arrays
This problem is very similar to ‘Arrays with Length 1’, but with a minor difference. In ‘Arrays with Length 1’ problem, length of the primitive array is 1 and there is only 1 element in the array, whereas in this pattern, length of the primitive array can be more than 1, but it has only 1 valid element. Remaining elements of the array will have ‘null’ values.
Inefficient Primitive Statistics
Fig 12.1: Important statistics about inefficient primitive array
HeapHero reports 3 important statistics about inefficient primitive array:
- Total Primitive Arrays: Total number of primitive arrays present in the application.
- Inefficient Primitive Arrays: Number of inefficient primitive arrays present in the application. As per the above example, there are 1,875,695 total primitive arrays present in the application. Out of it, 57,618 primitive arrays are inefficient.
- Wasted Memory: The amount of memory wasted due to inefficient primitive arrays in the application. In this example, it’s 24.5 MB i.e.5.8% of overall memory. If we remove all inefficient primitive arrays, we can save 24.5 MB of memory.
Top Inefficient Primitive Arrays
Fig 12.2: Top inefficient primitive arrays present in the application
This section shows the top inefficient primitive arrays present in the application. According to the example given in Fig 12.2, 6% of “byte[]” in the application contains a lot of 0s. These type of primitive arrays occupy 8.12 MB i.e. 1.9% of memory.
Who is holding Inefficient Primitive Arrays?
Fig 12.3: What objects are holding on to inefficient primitive arrays
This section of the report shows large objects that are holding on to inefficient primitive arrays in the application. According to the example given in Fig 12.3, the overall size of object “java.nio.HeapByteBuffer.hb” is 1,737 kb and it occupies 0.4% of memory. You can click on this object to see the complete object tree as shown in Fig 12.4.
Fig 12.4: Object tree
This section of the report shows object tree of “java.nio.HeapByteBuffer.hb” i.e. basically parent, grandparent, great-grandparent,… of “java.nio.HeapByteBuffer.hb”. This tree will help you identify the part of your source code that originates this memory overhead.
How to fix Inefficient Primitive Arrays?
This section of HeapHero provides recommendations to fix the inefficient primitive arrays in your application. However, it’s available only in Enterprise Edition.
13. Boxed Numbers
Since primitive data types such as ‘int’, ‘long’, ‘float’… can’t be used in Collections, developers convert them to boxed wrapper objects ‘Integer’, ‘Long’, ‘Float’,… However, these boxed objects add considerable memory overhead to the application. A primitive ‘int’ data type occupies 4 bytes. On the other hand, Integer object occupies 16 or 24 bytes (depending on whether the JVM runs in the “narrow pointer” or “wide pointer” mode). Additional 4 or 8 bytes for the pointer to object. Thus, you can see the amount of overhead added to use the boxed wrapper objects. Few bytes might not make big difference, however, this problem compounds to a big number especially when there are hundreds/thousands of boxed objects in the application.
HeapHero detects the amount of memory wasted due to boxed numbers in your application and reports them under the “Boxed Numbers” section of the report. Let’s review the details of this section.
Boxed Number Statistics
Fig 13.1: Important statistics about Boxed Numbers
HeapHero reports 2 important statistics about boxed numbers:
- Total Boxed Objects: Reports the total number of boxed objects (i.e. Integer, Float, Double, Long..) in the application. In this application, there are 425,344 boxed objects
- Wasted Memory: Assume if the application would have used primitives instead of boxed objects, it would have saved 6.93mb of memory. This accounts for 1.7% memory of the overall memory utilization.
Top Boxed Numbers
Fig 13.2: Top Boxed Numbers in the memory
This section shows the top boxed objects that present in the application. According to the example given in Fig 13.2, there are 309,829 instances of “java.lang.Integer” objects. These many boxed numbers occupy 4.73mb i.e. 1.1% of overall memory. In other words, if we can eliminate all the instances of “java.lang.Integer”, we will be able to reduce the memory size by 4.73mb.
Who is holding Boxed Numbers?
Fig 13.3: What Objects are holding on to Boxed Numbers
This section of the report shows the large objects that are holding on to Boxed Numbers in the application. According to the example given in Fig 13.3, “{java.util.TreeMap}.keys” object holds a lot of boxed numbers. This object’s overall size is 589KB and it occupies 0.1% of memory. You can click on the first column (i.e. “{java.util.TreeMap}.keys”), to see the complete object tree as shown in Fig 13.4.
Fig 13.4: Object Tree
This section of the report shows the object tree of “{java.util.TreeMap}.keys” i.e. basically parent, grandparent, great-grandparent,… of “{java.util.TreeMap}.keys”. This tree will help you identify the part of your source code that originates this memory overhead.
How to fix Boxed Numbers?
This section of HeapHero provides recommendations to fix the Boxed Numbers in your application. However, it’s available only in Enterprise Edition.
14. Objects Waiting for Finalization
Objects that have finalize() method are treated differently during garbage collection process than the ones which don’t have. During garbage collection phase, objects with finalize() method aren’t immediately evicted from the memory. Instead, as the first step, those objects are added to an internal queue of java.lang.ref.Finalizer. For entire JVM, there is only one low priority JVM thread by name ‘Finalizer’ that executes finalize() method of each object in the queue. Only after the execution of finalize() method, object becomes eligible for Garbage Collection. Assume if your application is producing a lot of objects which has finalize() method and low priority “Finalizer” thread isn’t able to keep up with executing finalize() method, then significant amount unfinalized objects will start to build up in the internal queue of java.lang.ref.Finalize, which would result in significant amount of memory wastage.
Sometimes because of poor programming practice, “Finalizer” thread may start to WAIT or BLOCK while executing the finalize() method. If “Finalizer” thread starts to wait or block, then the number of unfinalized objects in the internal queue of ‘java.lang.ref.Finalizer’ will start to grow significantly. It would result in OutOfMemoryError, jeopardizing entire JVM’s availability.
HeapHero detects the amount of memory wasted due to the objects in the application waiting to be finalized. This information is reported under the “Objects waiting for Finalization” section of the report. Let’s review the details of this section.
Objects waiting for Finalization statistics
Fig 14.1: Memory wasted due to Objects waiting for finalization
HeapHero reports the amount of memory wasted due to objects waiting for finalization of your application. In this hypothetical example, 7.66 MB i.e. 97.2% is the amount of memory that is wasted. If you are going to eliminate all the objects waiting for finalization, then you can save 7.66 MB of memory.
What are the objects waiting for finalization?
Fig 14.2: Object Tree
This section of the report shows the object tree of “j.l.r.ReferenceQueue” (note this is queue of ‘java.lang.ref.Finalizer’ object that holds the reference to all objects, whose finalize() method needs to be executed). If you drill down the tree, it will show the objects that are sitting in the queue waiting to be finalized. According to the example given in Fig 14.2, you can see 2 types of objects that are sitting in the queue:
- com.petals.finalize.SampleObject.data occupying 56.8% of memory
- com.petals.finalize.SampleObject occupying 11.5% of memory
How to fix objects waiting for finalization?
This section of HeapHero provides recommendations to fix objects waiting for finalization of your application. However, it’s available only in Enterprise Edition.
15. Heap Setting Recommendation
HeapHero uses intelligence algorithms to give recommendations for your heap size settings. These recommendations have potential to save considerable amount of memory.
16. System Properties
Fig 16.1: System Properties
HeapHero prints all the system properties that are passed to the application in a table, as shown above.
17. Report Sharing
Fig 17.1: Share Report hyperlink
Fig 17.2: Generating Report sharing URL
Heap dump files are huge in size and hard to circulate among your team members. It’s much easier to share the generated report. HeapHero provides an option to share the report among your team members. At the right top corner of the report, there is a ‘Share Report’ hyperlink. When you click on this hyperlink, it will generate a URL. When this URL is pasted into the browser, it will take you the report. For collaboration purposes, this URL can be circulated among your team members.