12

I would like to ask you HOW (or IF) is possible to reduce Spring framework's RAM footprint.

I created a simple helloworld app for demonstrating the issue. There are only two classes and context.xml file:

  • Main - class with main method
  • Test - class used for simulating some "work" (printig Hello in endless loop)

context.xml contains only this:

<context:component-scan base-package="mypackage" />

Test class contains only metod called init, called after construction:

@Component
public class Test{

    @PostConstruct
    public void init() {
        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    while (true) {
                        System.out.println("Hello " + Thread.currentThread().getName());
                        Thread.sleep(500);
                    }
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        });
        t.start();
    } 
}

I prepared two scenarios and in both of them main method contains only one line.

In first scenario main method does this: (new Test()).init(); App works without Spring and consumes only aprox. 8MB of RAM.

In second scenario main method contains following: new ClassPathXmlApplicationContext(new String[]{"spring/context.xml"}); So the app is initialized throug Spring container and consumes aprox. 45MB of RAM !

Is there any way how to reduce (in best case completely get rid of) this extra memory ? So far I wasn't able to find any fitting solution.

I don't mind if there is the extra memory consumption on startup - this is perfectly fine, but after that, I need our app to reduce it.

(The story behind this question is a bit more complicated, but this is for me now the core problem.)

Thank you

Markus Malkusch
  • 7,738
  • 2
  • 38
  • 67
Kousalik
  • 3,111
  • 3
  • 24
  • 46
  • 1
    how did you measure the memory consumption? – injecteer Mar 05 '14 at 15:35
  • If you want to use Spring as DI container, I would suggest you to try out something more lightweight like Guice or Dagger. – Milan Baran Mar 05 '14 at 15:35
  • 1
    This is only a idea, (I do not know if it work): I would expect, that you can reduce the footprint (PermGen) when you use spring java based configuration instead of xml configuration, because I expect that spring then will not load the xml libaries for reading the file. – Ralph Mar 05 '14 at 18:12
  • @injecteer I'm using windows task manager, because the actually alocated memory is the only memory that matters to me. And for everything else I use JProfiler – Kousalik Mar 06 '14 at 21:30
  • @Ralph using only annotation config saves only 2M. – Kousalik Mar 10 '14 at 09:20

1 Answers1

33

First a few things which you may already know but are important to understand the situation: most of the memory your program uses is the JVM heap. The heap has an initial size when your program starts executing. Sometimes the JVM will ask the OS for more memory and increase the size of the heap. The JVM will also perform garbage collection, thus freeing space in the heap.

When the used heap size diminishes, memory is not necessarily released by the JVM. The oracle JVM is reluctant to do so. For example if your program uses 500 MB of ram on startup, then after garbage collection only uses 100 MB for most of its execution, you cannot assume the additional 400 MB will be given back to your OS.

Furthermore, tools like the windows task manager (and I assume unix's ps) will display the size of all the memory that is allocated to the JVM, regardless of whether this memory is actually used or not. Tools like jvisualvm will let you see exactly how the memory is used in your java program, and in particular what amount of heap you're actually using vs. how much is allocated.


With this in mind I tested your program in the following scenarios. Note that this depends on many factors including which JVM you use, its version, and probably your OS too.

  • Standard java (SE) vs Spring.
  • Garbage collection (GC) vs none (NOGC) (I called the garbage collector from jvisualvm).
  • Minimum heap size defined for the JVM (using -Xmx8M). This tells the JVM to only allocate 8MB on startup. The default on my system is 256MB.

For each case I report the allocated heap size and used heap size. Here are my results:

  • SE, NOGC, 256M : 270 MB allocated, 30 MB used
  • Spring, NOGC, 256M : 270 MB allocated, 30 MB used

These results are identical, so from your question I assume you already had a different environment than I did.

  • SE, GC, 256M : 270 MB allocated, 9 MB used

Using the GC reduces heap usage, but we still have the same allocated memory

  • SE, NOGC, 8M : 9 MB allocated, <5 MB used
  • Spring, NOGC, 8M : 20 MB allocated, <5 MB used

This is the most important result: more memory is allocated because Spring probably needs more at some point during startup.

Conclusions:

  • If you're trying to reduce heap usage, using spring should not be much of a problem. The overhead is not gigantic.
  • If you're trying to reduce allocated memory, the price of using Spring, in this experiment, is steeper. But you can still configure your JVM so that it will free memory more often than the default. I don't know much about this, but jvm options such as -XX:MaxHeapFreeRatio=70 might be a start (more here http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#PerformanceTuning )
Charles Goodwin
  • 6,402
  • 3
  • 34
  • 63
ARRG
  • 2,476
  • 17
  • 28
  • Hello, thx for your exhaustive answer. My measuring is done on Win 7, Oracle JVM 1.7 32bit. I'm pretty much aware of these teoretical memory stuff in Java, same with VM options (VM tunning was fist thing we have done). I'm actually using JProfiler for profiling. Only memory consumption I care, is the allocated amount. For example with Spring task manager says, it consumes 45M - and Jprofiler says that heap has 125M (21M used - msotly with reflection Strings in SPring's hashmaps) and without Spring task manager says, it consumes 10M - and Jprofiler says thah heap has 122M (7M used). – Kousalik Mar 06 '14 at 08:49
  • Your last point is the most fitting to my issue, I'll take a look at it, if I didn't missed something. – Kousalik Mar 06 '14 at 08:52
  • 1
    So, with further tweaking VM, I have still 8M without Spring and 28M (15+M improvement, but still too much). According to JProfiler the amount of used heap space is 3M(1,5M without Spring - not really a diference) but the non-heap space is 8M (1M without Spring). Is there a chance how to reduce this ? – Kousalik Mar 06 '14 at 11:00
  • Sorry mate, it's been some time since this question. See my last comment. I don't think I got any further. – Kousalik Jan 03 '18 at 08:58