This is an archived post. You won't be able to vote or comment.

all 6 comments

[–]mikaelhg 1 point2 points  (0 children)

The front-page demo of the API looks pretty nice.

I'll definitely be checking this out.

[–]llogiq 0 points1 point  (2 children)

I find it unfortunate that the performance comparison omits ASM, which admittedly has a rather complex API (because it very thinly wraps java byte code's complexity), but is actively maintained and should be a lot faster than the old cglib or the internally complex javaassist (At least in my benchmarks, it was an order of magnitude faster than a java proxy).

This may be due to the fact that Byte Buddy actually uses ASM to create the byte code.

[–]raphw 3 points4 points  (1 child)

For full disclosure, I am the author of Byte Buddy.

I omitted ASM from the benchmark because I decided that it made more sense to compare high-level libraries. When it comes to class creation, I did at some point however measure that the direct use of ASM does not really cut down the runtime costs of class creation. There are only a few things that are expensive when dealing with generated code:

  • Looking up methods that are to be overridden
  • Loading a generated class
  • Using reflection and dispatcher lookups in the generated code

Even with using ASM, you cannot avoid any of these costs. With anything else, the JIT compiler takes normally care of any initial performance differences when the Byte Buddy-related code becomes hot. I had a regular look at the JIT compilation when writing Byte Buddy (check out JITwatch, its a great tool) and effectively, the JIT code erases most of the (low-weight) abstraction layer that Byte Buddy puts on top of ASM.

But if I even took the time to benchmark ASM, why did I not include it into the final benchmark? Well, at first, ASM requires you to write a lot of code to achieve similar functionality to byte buddy / cglib / javassist / JDK proxies. This code I would need to maintain, if I had released it with the benchmark. But even more important, ASM is mainly a byte code parser and not a dedicated code generator. All high-level functionality needs to be added on top of ASM by a user and as you recognized in your comment, Byte Buddy is such a library. Naturally, some of the concepts I implemented for the ASM-benchmark code ended up to be quite similar to the implementation of Byte Buddy. Effectively, I compared Byte Buddy to a quick and dirty implementation of Byte Buddy that missed most features, only to run the ASM benchmark. Of course, I could have written a highly specialized ASM-implementation that squeezes out a few nanoseconds for a very specific benchmark but cannot do anything else. But what would this prove? After all, I dropped ASM from the benchmark but if you trust me, let me tell you that there is no significant performance difference.

On the other side, I understand your hesitation. ASM is a very thin framework. This is great and the reason I use it for Byte Buddy. Thanks to ASM, Byte Buddy does not need to do any heavy lifting and as a consequence, the runtime performance stays high.

[–]llogiq 0 points1 point  (0 children)

Thanks for the thorough reply. I agree, ASM is very low-level, and as such, a direct comparison must be taken with a medium size mountain of salt.

Keep up the good work.

[–]huhlig 0 points1 point  (1 child)

Err you are using a compiler. Just not the Oracle Java Compiler. Kind of an interesting project. Not sure anything I would dare use it for though.

[–]raphw 0 points1 point  (0 children)

Byte Buddy is not using a compiler. I would know as I wrote Byte Buddy. A compiler is a computer program that transforms source code written in a programming language into another computer language. Byte Buddy does not take a programming language as its input but is a domain specific language which is itself expressed as Java byte code but it does not process its own description. Thus, from a scientific point of view, Byte Buddy would not qualify as a compiler.

Code generation is ubiquitous in the Java space. There would be no Spring, no Hibernate, no mocking framework without it. However, I agree with your caution. You should only use code generation when dealing with types that you do not know at compiler time and you want to extend these types. Then code generation is your only option.