Calculating Memory Usage of an Array

This section provides a tutorial example on how to calculate memory usage of a large array.

The memory information provided by the JVM can be used to calculate the memory usage of data objects used in the application program. In the following program, I tried to calculate the memory usage of an array:

/* MemoryUsage.java
 * Copyright (c) HerongYang.com. All Rights Reserved.
 */
public class MemoryUsage {
   private static long[] fm = new long[2];
   private static long[] tm = new long[2];
   private static long[] mm = new long[2];
   private static long[] um = new long[2];
   public static void main(String[] a) {
      Runtime rt = Runtime.getRuntime();
      getMemoryInfo(rt,0);
      long[] la = null;
      long s = allocateLongArray(la);
      getMemoryInfo(rt,1);
      System.out.println("Memory usage before array allocation:");
      System.out.println("   Free memory = "+fm[0]);
      System.out.println("   Total memory = "+tm[0]);
      System.out.println("   Maximum memory = "+mm[0]);
      System.out.println("   Memory used = "+um[0]);
      System.out.println("Memory usage after array allocation:");
      System.out.println("   Free memory = "+fm[1]);
      System.out.println("   Total memory = "+tm[1]);
      System.out.println("   Maximum memory = "+mm[1]);
      System.out.println("   Memory used = "+um[1]);
      System.out.println("Memory usage summary:");
      System.out.println("   Allocated to the array = "+s);
      System.out.println("   Memory usage increase = "+(um[1]-um[0]));
      System.out.println("   Overhead of single array = "
         +(um[1]-um[0]-s));
   }
   public static void getMemoryInfo(Runtime rt, int i) {
      fm[i] = rt.freeMemory();
      tm[i] = rt.totalMemory();
      mm[i] = rt.maxMemory();
      um[i] = tm[i]-fm[i];
   }
   public static long getMemoryInfo(Runtime rt) {
      //rt.gc();
      System.out.println("Getting JVM memory information...");
      long fm = rt.freeMemory();
      long tm = rt.totalMemory();
      long mm = rt.maxMemory();
      System.out.println("   Free memory = "+fm);
      System.out.println("   Total memory = "+tm);
      System.out.println("   Maximum memory = "+mm);
      System.out.println("   Memory used = "+(tm-fm));
      return tm-fm;
   }
   public static long allocateLongArray(long[] la) {
      int s = 2*128*1024;
      la = new long[s]; // 2 MB needed for this array
      return 8*s;
   }
}

Output:

Memory usage before array allocation:
   Free memory = 1777248
   Total memory = 2031616
   Maximum memory = 134217728
   Memory used = 254368
Memory usage after array allocation:
   Free memory = 1897280
   Total memory = 4132864
   Maximum memory = 134217728
   Memory used = 2235584
Memory usage summary:
   Allocated to the array = 2097152
   Memory usage increase = 1981216
   Overhead of single array = -115936

The output was very surprising. An array for storing 2097152 bytes (2MB) of data was allocated. But the memory usage was increased by only 1981216 bytes. Somehow the JVM freed up some memory during the array allocation process.

If you look closely on the values of total memory before and after the array allocation, you can see that the JVM had requested an additional 2MB of memory from the operating system into order to have enough memory to give to the array. My guess is that the expansion of total memory triggered a garbage collection call, which removed some un-used objects in the JVM.

One way to avoid the total memory expansion is to invoke the JVM with a starting total memory of 4MB, using the following command:

herong> java -Xms4m MemoryUsage

Output:

Memory usage before array allocation:
   Free memory = 3874400
   Total memory = 4128768
   Maximum memory = 134217728
   Memory used = 254368
Memory usage after array allocation:
   Free memory = 1777232
   Total memory = 4128768
   Maximum memory = 134217728
   Memory used = 2351536
Memory usage summary:
   Allocated to the array = 2097152
   Memory usage increase = 2097168
   Overhead of single array = 16

This time the program worked as I expected. The memory usage increased 16 bytes more than the number of bytes needed to store the data elements of the array. So the 16 bytes is the overhead cost of memory for a one-dimension array. It is used to store the size of the array and other information about the array.

Table of Contents

 About This Book

 JDK - Java Development Kit

 Execution Process, Entry Point, Input and Output

 Primitive Data Types and Literals

 Control Flow Statements

 Bits, Bytes, Bitwise and Shift Operations

 Managing Bit Strings in Byte Arrays

 Reference Data Types and Variables

 Enum Types and Enum Constants

 StringBuffer - The String Buffer Class

System Properties and Runtime Object Methods

 JVM and OS System Properties

 System.setProperty() - Setting Your Own Properties

 Runtime.getRuntime() - Getting the Runtime Object

 freeMemory() - Getting JVM Free Memory Information

Calculating Memory Usage of an Array

 exec() - Executing Operating System Commands

 Generic Classes and Parameterized Types

 Generic Methods and Type Inference

 Lambda Expressions and Method References

 Java Modules - Java Package Aggregation

 Execution Threads and Multi-Threading Java Programs

 ThreadGroup Class and "system" ThreadGroup Tree

 Synchronization Technique and Synchronized Code Blocks

 Deadlock Condition Example Programs

 Garbage Collection and the gc() Method

 Assert Statements and -ea" Option

 Annotation Statements and Declarations

 Java Related Terminologies

 Archived Tutorials

 References

 Full Version in PDF/EPUB