Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cost of each class in Java application - Fewer huge classes or Several smaller ones

For every new Class added to a Java application, what is the cost in terms of memory?

  • Is it better to have huge 5000+ lines classes or several 500-1000 line classes (if all of them are loaded anyway)
  • Each time an Object is instantiated is it true that the only additional memory usage is for the instance variable references
  • For a 5000-line class with no instance variables, what is the scale of cost when the class is loaded.. is the size of the class file a rough approximation?
  • Is the size of the jar file any indication of either usual or max size of memory that classes will occupy?

Edited after cruftex's answer: This is my understanding of class splitting:

  • Splitting into logical blocks could very well improve code reuse and reduce number of lines
  • It also makes it easier to understand and maintain code

This is my understanding of class loading now:

  • On first use Class is loaded into memory (Memory used is roughly the size of the class file)
  • If JIT is used, some additional machine-friendly binary version is created by the JIT compiler which uses a little more memory
  • If Hotspot is used only some of the frequently used classes are optimised with machine-friendly versions (to balance memory and speed)
  • Once a class is loaded, creating additional instances has negligible overhead (about 50-100 bytes?) (assuming no instance variables)
  • Once a class is loaded the class itself is never garbage collected

Is this roughly how it works?

like image 398
Teddy Avatar asked Mar 01 '14 04:03

Teddy


2 Answers

For every new Class added to a Java application, what is the cost in terms of memory?

It usually doesn't matter. Generally speaking, only a small proportion (say, 5%) of overall memory use is taken up by code in its various forms. Therefore, even if you did manage to reduce code size by half, overall memory usage would decrease only marginally.

In contrast, overly long source files make a code base hard to navigate, and the larger scopes make it harder to get an overview of what exactly the class does and whether a certain change is safe. Therefore, long source files make modifying the code significantly more expensive and error prone.

  • On first use Class is loaded into memory (Memory used is roughly the size of the class file)

Correct.

  • If JIT is used, some additional machine-friendly binary version is created by the JIT compiler which uses a little more memory
  • If Hotspot is used only some of the frequently used classes are optimised with machine-friendly versions (to balance memory and speed)

Hotspot is a JIT, so you're repeating yourself here. But yes, JIT does increase code size (but increases speed far more).

Once a class is loaded, creating additional instances has negligible overhead (about 50-100 bytes?) (assuming no instance variables)

That is JVM specific. On the Oracle Hotspot JVM, memory overhead per object is about 8 bytes, as the following program demonstrates:

public class Test {
    public static void main(String[] args) {
        Object[] array = new Object[10_000_000];
        Runtime rt = Runtime.getRuntime();
        long usedBefore = rt.totalMemory() - rt.freeMemory();
        for (int i = 0; i < array.length; i++ ) {
            array[i] = new Object();
        }
        long usedAfter = rt.totalMemory() - rt.freeMemory();
        System.out.println(usedBefore);
        System.out.println(usedAfter);
        System.out.println((double)(usedAfter - usedBefore) / array.length);
    }
}
  • Once a class is loaded the class itself is never garbage collected

While it is not mandated by the Java Language Specification, every JVM I ever used frees a class when its ClassLoader becomes unreachable (granted, the bootstrap class loader will always remain reachable, but custom ClassLoaders can become unreachable).

like image 122
meriton Avatar answered Nov 12 '22 10:11

meriton


You question cannot be answered specific, so I try it in a general way. Your questions aim at memory consumption. However, if you save memory it is most likely that your performance suffers from that, that is called space time trade off. See: http://en.wikipedia.org/wiki/Space%E2%80%93time_tradeoff

The easiest way to save memory - if you are only concerned of your program size - would be to switch off the just in time compiler completely. This way you save the program storage for the machine code of your java classes. BTW: There are a lot of VM options that impact the memory consumption!

Is it better to have huge 5000+ lines classes or several 500-1000 line classes (if all of them are loaded anyway)

In general the chances are more likely that you can reuse code better within smaller units. Which means, you probably save code lines when aiming at smaller sizes.

If the code/methods stay the same and you just distribute them between classes, then an additional overhead adds for the classes.

Even if you ask three experts on that and they have a look at the code, they will come up with different answers, because it heavily depends on your real code, the usage patterns and what the JIT is doing with it at runtime.

That said, even an experiment might lead you in the wrong direction, because you need to simulate the same usage patterns.

A last note on that: Take a look on how many classes your VM loads and decide whether it is really worth saving a view.

Each time an Object is instantiated is it true that the only additional memory usage is for the instance variable references

Plus a constant overhead for memory management.

For a 5000-line class with no instance variables, what is the scale of cost when the class is loaded.. is the size of the class file a rough approximation?

Without the JIT: yes.

Is the size of the jar file any indication of either usual or max size of memory that classes will occupy?

No, not at all, because the classes are only loaded when needed.

Some advice:

If you are concerned about the memory usage of your program, first check the heap twice. I recommend jmap and eclipse memory analyzer for that.

Then, you may have a look on your classes and methods. You can debug the JIT and see how much space the compiled methods are needing by: -XX:-PrintCompilation.

like image 22
cruftex Avatar answered Nov 12 '22 08:11

cruftex