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?
解决方案
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
Have a single thread running.
Create a new array to store your objects to allocate. So these objects won't be collected during GC run.
System.gc(), memoryBefore = runtime.totalMemory() - runtime.freeMemory()
Allocate your objects. Put them into the array.
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.