Using the NetBeans Profiler Programmatically in Java
This article explores how to use the NetBeans Profiler API to collect heap dumps, analyze memory usage, and inspect specific class instances programmatically within a Java application. We will explore using the NetBeans Profiler API to analyze performance metrics in Java applications programmatically. Rather than relying on VisualVM or GUI-based tools, programmatic profiling provides a flexible way to collect data from running applications and output it directly to the console or logs.
1. Introduction to NetBeans Profiler API
The NetBeans Profiler is an effective tool for identifying performance bottlenecks, memory leaks, and usage patterns in Java applications. While its graphical interface is useful for in-depth profiling, accessing the profiler programmatically offers a streamlined, automated approach. The NetBeans Profiler API, available in the open-source NetBeans repository, enables programmatic access to profiling tools within the NetBeans IDE, allowing us to capture essential performance data directly in our code.
2. Setting up a Sample Project
To begin, a simple Maven project should be set up, including the NetBeans Profiler API. If the profiler is not directly available, the NetBeans repository may need to be added. Here is an example pom.xml
configuration:
<dependencies> <!-- NetBeans Profiler dependency --> <dependency> <groupId>org.netbeans.modules</groupId> <artifactId>org-netbeans-lib-profiler</artifactId> <version>REPLACE_WITH_VERSION</version> </dependency> </dependencies> <repositories> <repository> <id>netbeans</id> <name>netbeans</name> <url>http://bits.netbeans.org/maven2</url> </repository> </repositories>
Replace REPLACE_WITH_VERSION
with the appropriate version for the NetBeans Profiler API.
3. Using the NetBeans Profiler API Programmatically
We will create a simple Java project that performs computational tasks and allocates memory, enabling us to analyze its performance using the NetBeans Profiler API. Let’s create a Library
management system as an example, where each Library
has books, sections, and other attributes. This class will simulate memory usage and provide data we can inspect in a heap dump.
public class Library { private int id; private String name; private List<String> books = new ArrayList<>(); private List<String> sections = new ArrayList<>(); public Library(int id, String name) { this.id = id; this.name = name; } public void addBook(String bookName) { books.add(bookName); } public void addSection(String sectionName) { sections.add(sectionName); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getBooks() { return books; } public void setBooks(List<String> books) { this.books = books; } public List<String> getSections() { return sections; } public void setSections(List<String> sections) { this.sections = sections; } }
In this example:
Library
has attributes likeid
,name
,books
, andsections
.- The
addBook
andaddSection
methods allow adding books and sections to the library.
4. Taking a Heap Dump
To capture heap dumps programmatically, we will use a utility class named HeapDumpUtility
. This class leverages the HotSpotDiagnosticMXBean
from the com.sun.management
package to trigger a heap dump at a specific point in the application.
import java.io.IOException; import java.lang.management.ManagementFactory; import com.sun.management.HotSpotDiagnosticMXBean; public class HeapDumpUtility { private static final String HOTSPOT_BEAN_NAME = "com.sun.management:type=HotSpotDiagnostic"; private static volatile HotSpotDiagnosticMXBean hotspotMBean; public static void dumpHeap(String filename, boolean live) throws IOException { initHotspotMBean(); hotspotMBean.dumpHeap(filename, live); } private static void initHotspotMBean() throws IOException { if (hotspotMBean == null) { synchronized (HeapDumpUtility.class) { hotspotMBean = ManagementFactory.newPlatformMXBeanProxy( ManagementFactory.getPlatformMBeanServer(), HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean.class); } } } }
This HeapDumperUtility
class uses the HotSpotDiagnosticMXBean to dump the heap into a file.
5. Analyzing the Heap Dump
Once the heap dump is created, we can load it into VisualVM or the NetBeans Profiler’s GUI to examine memory usage. In this example, however, we utilize NetBeans’ built-in in-code APIs to analyze heap dumps directly through code. Below is an example of how to load and analyze a heap dump programmatically using the NetBeans API:
import java.io.File; import java.io.IOException; import org.netbeans.lib.profiler.heap.HeapSummary; import org.netbeans.lib.profiler.heap.Heap; import org.netbeans.lib.profiler.heap.HeapFactory; public class ProfilingExample { private static Heap heap; private static void analyzeHeapDump() throws IOException { heap = HeapFactory.createHeap(new File("heapdump.hprof")); HeapSummary summary = heap.getSummary(); System.out.println("Total number of instances: " + summary.getTotalLiveInstances()); System.out.println("Memory usage in bytes: " + summary.getTotalLiveBytes()); System.out.println("GC Roots: " + heap.getGCRoots().size()); System.out.println("Total number of Classes: " + heap.getAllClasses().size()); System.out.println("Timestamp: " + summary.getTime()); } public static void main(String[] args) throws IOException { Library cityLibrary = new Library(1, "Programming Library"); cityLibrary.addBook("Java Programming Essentials"); cityLibrary.addBook("Data Structures and Algorithms"); cityLibrary.addSection("Technology"); cityLibrary.addSection("Literature"); Library homeLibrary = new Library(1, "Philosophical Library"); homeLibrary.addBook("Age of Reason"); homeLibrary.addBook("The Principles of Nature"); homeLibrary.addSection("Philosophy"); File f = new File("heapdump.hprof"); if (f.exists()) { f.delete(); } HeapDumpUtility.dumpHeap("heapdump.hprof", true); analyzeHeapDump(); } }
In the main
method, two Library
instances (cityLibrary
and homeLibrary
) are created, each with sample data representing books and sections. After initializing these objects, the code calls HeapDumpUtility.dumpHeap()
to generate a heap dump file, heapdump.hprof
, which captures the current memory state, including object references and the structure of Library
instances and related data. This setup simulates a basic memory allocation scenario in which objects are created and stored for later analysis.
Following the heap dump creation, the analyzeHeapDump
method loads the heap dump file using the NetBeans Profiler API’s HeapFactory.createHeap()
method. This method generates a Heap
instance from the dump file, enabling programmatic analysis of the memory contents.
When the code runs, the output will display summary information about the heap dump, including details like the total number of instances, memory usage in bytes, GC roots, the total number of classes, and the timestamp of the dump. Below is an example output and a breakdown of each line:
These insights provide a snapshot of the memory footprint of the running application at the time of the dump, offering a straightforward way to assess memory allocation and usage within the Library
instances. Here is a summary of each output line:
- Total instances: 31,679 live objects in memory
- Memory usage: 1,836,066 bytes of memory allocated (approximately 1.84 MB).
- GC Roots: 1,418 objects reachable by garbage collection
- Total classes: 1,526 unique classes loaded in the heap
- Timestamp: 1731436123085 (time of heap dump creation)
5.2 Analyzing Library Class Instances
In this section, we analyze the memory usage and number of instances for the Library
class within the heap dump. The following code retrieves the Library
class from the heap and calculates its memory consumption:
public static void librarySummary() { JavaClass libraryClass = heap.getJavaClassByName("com.jcg.profilingexample.Library"); if (libraryClass == null) { System.out.println("Library class not located"); return; } List<Instance> instances = libraryClass.getInstances(); long totalSize = 0; long instancesNumber = libraryClass.getInstancesCount(); for (Instance instance : instances) { totalSize += instance.getSize(); } System.out.println("Number of Library instances: " + instancesNumber); System.out.println("Memory consumed by Library instances: " + totalSize); }
This block of code starts by looking for the Library
class in the heap using heap.getJavaClassByName("com.jcg.profilingexample.Library")
. If the class is not found, it prints a message and exits the method. If the class is found, it retrieves all instances of the Library
class using libraryClass.getInstances()
and counts how many instances of the class exist in the heap with libraryClass.getInstancesCount()
.
Next, it calculates the total memory used by all instances of the Library
class by summing the size of each instance. This is done by iterating over the list of instances and adding up the size of each one using instance.getSize()
.
Example output:
Number of Library instances: 2 Memory consumed by Library instances: 88
Explanation of Output:
- Number of Library instances: 2 – This output indicates that there are a total of 2 instances of the
Library
class in memory. ThegetInstancesCount()
method counts how manyLibrary
objects are present within the heap dump. - Memory consumed by Library instances: 88 – This shows the total memory usage (in bytes) by all
Library
instances in the heap. ThegetSize()
method is used to sum up the memory taken up by each individualLibrary
object, giving the total memory usage.
6. Conclusion
In this article, we explored how to use the NetBeans Profiler API to capture and analyze heap dumps in a Java application. We demonstrated how to create and analyze a heap dump to inspect the memory usage and number of instances of a specific class. By using the provided code, we were able to track the total number of Class instances and their memory consumption, providing valuable insights into the memory behaviour of our application.
7. Download the Source Code
This article covered how to use the Java NetBeans profiler programmatically.
You can download the full source code of this example here: java netbeans use profiler programmatically