4

By default the HotSpot JIT refuses to compile methods bigger than about 8k of bytecode (1). Is there anything that can scan a jar for such methods (2)?

  1. unless you pass -XX:-DontCompileHugeMethods

  2. Jon Masamitsu describes how interpreted methods can slow down garbage collection and notes that refactoring is generally wiser than -XX:-DontCompileHugeMethods

James
  • 947
  • 2
  • 12
  • 20
  • 2
    I can sure see coming comments about why your code shouldn't have such big methods. Yet I'm sure there **are** legit ways end up with such big methods (like auto-generated state-machine code etc.). Btw, why are there so big methods in your code? – SyntaxT3rr0r Aug 05 '11 at 23:31
  • Some of our code has been around for 40 years and has had a hundred authors or more…there's no telling what was in some people's minds! (And obviously the Java >15 years old was originally written in some other language.) If there deep dark rarely-visited corners that exceed the 8k limit then they can stay. But I'd like to know if anything on the critical path is >8k, if it sneaks up >8k in the future, and if I'm refactoring I'd like to know when I get (far enough) below 8k. – James Aug 06 '11 at 11:14
  • You can use tools like javap and ASM to get the byte length of method – Peter Lawrey Aug 06 '11 at 12:29

2 Answers2

1

Thanks to Peter Lawrey for the pointer to ASM. This program prints out the size of each method in a jar:

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;

public static void main(String[] args) throws IOException {
    for (String filename : args) {
        System.out.println("Methods in " + filename);
        ZipFile zip = new ZipFile(filename);
        Enumeration<? extends ZipEntry> it = zip.entries();
        while (it.hasMoreElements()) {
            InputStream clazz = zip.getInputStream(it.nextElement());
            try {
                ClassReader cr = new ClassReader(clazz);
                ClassNode cn = new ClassNode();
                cr.accept(cn, ClassReader.SKIP_DEBUG);
                List<MethodNode> methods = cn.methods;
                for (MethodNode method : methods) {
                    int count = method.instructions.size();
                    System.out.println(count + " " + cn.name + "." + method.name);
                }
            } catch (IllegalArgumentException ignored) {
            }
        }
    }
}
James
  • 947
  • 2
  • 12
  • 20
  • I went ahead and modified it for my own needs - sorting! Here's a link to the code: http://paste.ubuntu.com/6095725/ Feel free to edit this in if anyone wants to. – Riking Sep 12 '13 at 06:09
  • @Riking My program and yours count the instructions; [this question](http://stackoverflow.com/questions/21357608/finding-the-bytecode-size-of-a-method) points out that the bytecode has more than one byte per instruction. Looking up the size of each instruction doesn't seem trivial. – James Mar 06 '14 at 03:17
  • 1
    I already noticed that, but! The restriction is on 8K bytecode **instructions**, not bytes! - which IS what is counted here. So that's not even necessary. – Riking Mar 06 '14 at 05:28
0

Checkstyle would probably be good for this - it doesn't work on the 8k limit but the number of executable statements in a method in general. To be honest, this is a limit that you want in practice though.

As you already state, -XX:-DontCompileHugeMethods is generally a bad idea - it forces the JVM to dig through all that ugly code and try and do something with it, which can have a negative effect on performance rather than a positive one! Refactoring, or better still not writing methods that huge to start with would be the way forward.

Oh, and if the methods that huge ended up there through some human design, and not auto-generated code, then there's probably some people on your team who need talking to...

Michael Berry
  • 70,193
  • 21
  • 157
  • 216