Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java unit testing: how to measure memory footprint for method call

Assuming I have a class that does some heavy processing, operating with several collections. What I want to do is to make sure that such operation can't lead to out-of-memory or even better I want to set a threshold of how much memory it can use.

class MyClass() {    public void myMethod()    {       for(int i=0; i<10000000; i++)       {          // Allocate some memory, may be several collections       }    } }  class MyClassTest {    @Test    public void myMethod_makeSureMemoryFootprintIsNotBiggerThanMax()    {       new MyClass().myMethod();        // How do I measure amount of memory it may try to allocate?    } } 

What is the right approach to do this? Or this is not possible/not feasible?

like image 261
Sergey Makarov Avatar asked Nov 05 '13 09:11

Sergey Makarov


People also ask

How to check memory usage of a method in Java?

Using VisualVM (jvisualvm) jvisualvm is a tool to analyse the runtime behavior of your Java application. It allows you to trace a running Java program and see its the memory and CPU consumption. You can also use it to create a memory heap dump to analyze the objects in the heap.

How is memory footprint calculated in Java?

First calculate the memory used before your code execution i.e. first line of your code. long afterUsedMem=Runtime. getRuntime(). totalMemory()-Runtime.

What is memory footprint in Java?

Memory footprint refers to the amount of main memory that a program uses or references while running. The word footprint generally refers to the extent of physical dimensions that an object occupies, giving a sense of its size.

What are a few ways you can improve the memory footprint of a Java application?

The most obvious place to start tuning the memory footprint is the Java heap size. If you reduce the Java heap size, you reduce the memory footprint of the Java process by the same amount. You cannot reduce the heap size beyond a point; the heap should be large enough for all objects that are live at the same time.


2 Answers

I can think of several options:

  • Finding out how much memory your method requires via a microbenchmark (i.e. jmh).
  • Building allocation strategies based on heuristic estimation. There are several open source solutions implementing class size estimation i.e. ClassSize. A much easier way could be utilizing a cache which frees rarely used objects (i.e. Guava's Cache). As mentioned by @EnnoShioji, Guava's cache has memory-based eviction policies.

You can also write your own benchmark test which counts memory. The idea is to

  1. Have a single thread running.
  2. Create a new array to store your objects to allocate. So these objects won't be collected during GC run.
  3. System.gc(), memoryBefore = runtime.totalMemory() - runtime.freeMemory()
  4. Allocate your objects. Put them into the array.
  5. System.gc(), memoryAfter = runtime.totalMemory() - runtime.freeMemory()

This is a technique I used in my lightweight micro-benchmark tool which is capable of measuring memory allocation with byte-precision.

like image 124
Andrey Chaschev Avatar answered Sep 24 '22 07:09

Andrey Chaschev


You can use profiler (for ex. JProfiler) for view memory usage by classes. Or , how mentioned Areo, just print memory usage:

    Runtime runtime = Runtime.getRuntime();     long usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory();     System.out.println("Used Memory before" + usedMemoryBefore);         // working code here     long usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory();     System.out.println("Memory increased:" + (usedMemoryAfter-usedMemoryBefore)); 
like image 38
pasha701 Avatar answered Sep 25 '22 07:09

pasha701