Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum exeeding the 65535 bytes limit of static initializer... what's best to do?

Tags:

I've started a rather large Enum of so called Descriptors that I've wanted to use as a reference list in my model. But now I've come across a compiler/VM limit the first time and so I'm looking for the best solution to handle this.

Here is my error : The code for the static initializer is exceeding the 65535 bytes limit

It is clear where this comes from - my Enum simply has far to much elements. But I need those elements - there is no way to reduce that set.

Initialy I've planed to use a single Enum because I want to make sure that all elements within the Enum are unique. It is used in a Hibernate persistence context where the reference to the Enum is stored as String value in the database. So this must be unique!

The content of my Enum can be devided into several groups of elements belonging together. But splitting the Enum would remove the unique safety I get during compile time. Or can this be achieved with multiple Enums in some way?

My only current idea is to define some Interface called Descriptor and code several Enums implementing it. This way I hope to be able to use the Hibernate Enum mapping as if it were a single Enum. But I'm not even sure if this will work. And I loose unique safety.

Any ideas how to handle that case?

like image 432
Daniel Bleisteiner Avatar asked Mar 30 '10 15:03

Daniel Bleisteiner


People also ask

Is exceeding the 65535 bytes limit Java?

Re: exceeding the 65535 bytes limit Wikipedia: A Java class or interface can have at most 65535 methods. The code of a constructor in Java is limited to 65535 bytes.

Is there a limit on enums?

An ENUM column can have a maximum of 65,535 distinct elements.

What is an enum in Java?

An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.

Can enum have multiple constructors?

Yes, they can have more than one constructor.


2 Answers

Simple. Don't use enum for this. You can't. It won't work.

The chances are that your source code does not explicitly refer to many of the enum values. Rather, you are using the enum as a convenient way to map between unique object instances and string names. So just replace the enum type with a type that explicitly manages the mapping, initializing it by reading from a file or database. If you do it right, you will get the computational properties and type-safety of an enum. The only thing you lose is the syntactic sugar ... and the statics.

This approach will have the added advantage that you can modify the 'descriptors' mapping without modifying the source code of your program.


By the way, the limitation you are running into is imposed by the JVM class file format. A method or constructor has an upper size limit of 2^16 bytes, and a classes static initialization code is represented as a special method with a funky name.

UPDATE

Unfortunately your self-answer solution will still run into a different 64K limit ... if pushed too far. Splitting the initialize() method gets around the method size limit, but there is also a 64K limit on the number of entries in a classes constant pool. Each String literal requires a constant pool entry.

like image 151
Stephen C Avatar answered Nov 16 '22 23:11

Stephen C


This is not a simple solution, but you may try to... patch the Java compiler.

When you write an enum, the Java compiler generate a class which extends java.lang.Enum (possibly several classes, if there are constant-specific methods). The class has some (hidden) static fields, which, at the bytecode level, are initialized with the special <clinit>() method (which the JVM calls when the class is first used). As any other method, the code for the <clinit>() method is limited to 65535 bytes. Each constant contributes to about 20 to 22 bytes in the <clinit>() bytecode (more if there are constant-specific constructors), so you hit the limit at about 3000 enumeration constants.

Now the <clinit>() method has a funny name but it is nothing really special; it can invoke other methods. The Java compiler could split the mammoth <clinit>() into several hidden sub-methods which <clinit>() would then invoke one after the other. The Java compiler does not currently do that, but it theoretically could. The result would be processable by any JRE.

Alternatively, synthesize your enum class synthetically, generating bytecode from a dedicated program, possibly itself written in Java. In essence, this is like writing your own specialized compiler, for a specific target and using your own source syntax. The BCEL library may help.

Note that there are other limits which could jump on you. For each enumeration constant, the static code (the one in <clinit>()) uses two "constants", which are internal values aggregated in the "constant pool" part of the compiled class. The two values are the constant name (as a string) and the resulting static field reference. There is a hard limit on 65536 constant pool entries (indexes are on 16 bits), so no more than a bit more than 32000 enumeration constants. A patched Java compiler could walk around that limit by generating several hidden classes, each with its own constant pool. A harder limit is in the number of static fields: each enumeration constant becomes a static field in the "enum" class, and there can be no more than 65535 fields (static or not) in a class.

like image 44
Thomas Pornin Avatar answered Nov 17 '22 00:11

Thomas Pornin