Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to make your Java application up to 60x faster with native images

How to make your Java application up to 60x faster with native images

In a world with more and more distributed applications e with no state control, one of the biggest challenges is performance (being related to startup or even to the response to the first request). This context made Java a big doubt for a while in approaches like serverless, microservices, and containers. But these times are over! Today there are not only platforms that take Java to a brand new performance level, but we also have something which allows us to take a step further: the native images. Join us in the session and learn what can and what cannot be done with native images, and how you can run your code 60x faster today.

Cad9d9d8998f49269ce4f28a018ba53e?s=128

Elder Moraes

June 07, 2021
Tweet

Transcript

  1. How to make your Java application up to 60x faster

    with native images Elder Moraes Developer Advocate @elderjava
  2. @elderjava 2 Demo: up to 60x faster

  3. @elderjava 3 Alert: this is *not* a Graal VM talk!

    This is! https://youtu.be/SivvH93gcco
  4. @elderjava 4 Thank you for your questions!

  5. @elderjava 5 A little bit of context

  6. @elderjava 6 Source: https://www.graalvm.org/community/opensource Native Image Builder

  7. @elderjava 7 Getting Started

  8. @elderjava 8 What is a native image? It’s a technology

    that uses AOT compilation to create a standalone executable
  9. @elderjava 9 How a native image is generated? • Using

    the Native Image Builder • It performs a static analysis of all classes (inside a project) and its dependencies
  10. @elderjava 10 • All methods and libraries used at runtime

    are mapped • So it Ahead of Time compiles this code generating a native executable for a specific OS and architecture How a native image is generated?
  11. @elderjava 11 What is embedded in a native image? •

    Application classes • Classes dependencies • Classes of runtime libraries • Static code native from JDK
  12. @elderjava 12 Nope! Do I need a JVM to run

    a native image?
  13. @elderjava 13 Serious? How it works? • Native images have

    a runtime system called Substrate VM • Some of its components are: memory management, thread scheduling, GC, etc.
  14. @elderjava 14 Limitations

  15. @elderjava 15 Limitations Assumptions • All runtime code needs to

    be known in the compile time • No new code is loaded in runtime • Not all applications are optmizable
  16. @elderjava 16 4 compatibility groups 1. Features that work, but

    require configuration 2. Features that might work differently 3. Features that don’t work 4. The rest (work out of the box) Limitations
  17. @elderjava 17 4 compatibility groups 1. Features that work, but

    require configuration 2. Features that might work differently 3. Features that don’t work 4. The rest (work out of the box) Limitations
  18. @elderjava 18 1. Features that work, but require configuration

  19. @elderjava 19 Dynamic class loading • Ex: Class.forName(“myClass”) • “myClass"

    needs to be in a configuration file • If the class isn’t available, throws ClassNotFoundException 1. Features that work, but require con fi guration
  20. @elderjava 20 Reflection • Classes, methods and fields accessed through

    reflection need to be known ahead-of-time • The Native Image Builder will map those elements using the calls to the Reflection API 1. Features that work, but require con fi guration
  21. @elderjava 21 Reflection • If the analysis fails, the elements

    must be informed in a configuration file • Class initializers can use reflection without restrictions 1. Features that work, but require con fi guration
  22. @elderjava 22 Dynamic Proxy • Supported if the bytecode were

    AOT generated • I.e, the list of interfaces that defines the proxies needs to be known in the build time 1. Features that work, but require con fi guration
  23. @elderjava 23 Dynamic Proxy • Mapped calls: • java.lang.reflect.Proxy.newProxyInstance •

    java.lang.reflect.Proxy.getProxyClass • If the static analysis fails, the interface list needs to be informed using a configuration file 1. Features that work, but require con fi guration
  24. @elderjava 24 JNI (Java Native Interface) • Very similar to

    Reflection (maps access to objects, classes, methods and fields) • For the same reasons, the items must be informed using a configuration file 1. Features that work, but require con fi guration
  25. @elderjava 25 JNI (Java Native Interface) • As an alternative,

    the native image package has its own native interface, much easier to use than the JNI • Ref: org.graalvm.nativeimage.c 1. Features that work, but require con fi guration
  26. @elderjava 26 Serialization • The metadata must be informed in

    a configuration file 1. Features that work, but require con fi guration
  27. @elderjava 27 2. Features that might work differently

  28. @elderjava 28 Signal Handlers • By default, no signal handler

    is registered in a native image • To be registered, the user must do it explicitly 2. Features that might work differently
  29. @elderjava 29 Signal Handlers • To register it, use the

    flag —install- exit-handlers when building the image • This option gives access to the same signal handlers provided by the JVM 2. Features that might work differently
  30. @elderjava 30 Class Initializers • By default, all classes are

    initialized during the image runtime • That ensures compatibility, but limits optimization • If initialized during build time, improves startup time and performance peak 2. Features that might work differently
  31. @elderjava 31 Class Initializers • For adjustments (for a class,

    a package or all classes): • --initialize-at-build-time • --initialize-at-run-time 2. Features that might work differently
  32. @elderjava 32 Finalizers • It's deprecated since Java 9 •

    Complex implementation for native images 2. Features that might work differently
  33. @elderjava 33 Threads • java.lang.Thread that are long deprecated are

    not implemented in the native images • Ex: Thread.stop() (deprecated since 1.2) 2. Features that might work differently
  34. @elderjava 34 Debug and Monitoring • Usually done using interfaces

    that assume the bytecode is available during runtime • What doesn’t happen with native images 2. Features that might work differently
  35. @elderjava 35 Debug and Monitoring • Option: use native tools

    • Ex: GDB (GNU Debugger) and VTune Profiler 2. Features that might work differently
  36. @elderjava 36 3. Features that don’t work

  37. @elderjava 37 invokedynamic • The method can change during the

    runtime (what can’t happen with native images) 3. Features that don’t work
  38. @elderjava 38 Security Manager • Not implemented in native images

    3. Features that don’t work
  39. @elderjava 39 Native Image vs JVM

  40. @elderjava 40 Faster startup • No classloading (all classes were

    loaded, linked and initialized) • No code being interpreted • No JIT • Part of the heap were generated during the compilation Native Image vs JVM
  41. @elderjava 41 Smaller memory footprint • No metadata for loaded

    classes • No profiling data for JIT optimizations • No cache for interpreted code • No JIT structures Native Image vs JVM
  42. @elderjava 42 So… why not using it for everything?

  43. @elderjava 43 Because there are no silver bullets!

  44. @elderjava 44 There’s no support for: • JVM TI (Java

    Virtual Machine Tool Interface) • Java Agents • JMX (Java Management Extensions) • JFR (Java Flight Recorder) Why not using native images for everything?
  45. @elderjava 45 Good for small heaps only: • GC is

    performed by the SerialGC available at SubstrateVM - very limited if compared to a "full" GC • If the heap is too big, the GC break the application performance Why not using native images for everything?
  46. @elderjava 46 There’s no runtime optimization • No JIT •

    All optimizations made during the compile time are final Why not using native images for everything?
  47. @elderjava 47 There’s no support for head dump and thread

    dump • Or there is… but only for Enterprise Edition Why not using native images for everything?
  48. @elderjava 48 When should I use native images?

  49. @elderjava 49 When your application: • Is small • Can

    be invoked multiples times in a short period of time • Has a short life cycle • Ex: CLI apps and serverless functions When should I use native images?
  50. @elderjava 50 Quarkus & Native Images

  51. @elderjava 51 • All Quarkus optimizations are*independent* of using native

    images or not • But, if you want to use it, Quarkus is 100% compatible (including its extensions) • You only need the Native Image Builder (through Graal VM or Mandrel) Quarkus & Native Images
  52. @elderjava 52 Mandrel & Graal VM

  53. @elderjava 53

  54. @elderjava 54 • Forked from Graal VM CE • In

    general: OpenJDK + Native Image Builder • Focused on Quarkus support • Better support for Red Hat customers • Better contribution for the whole Graal VM CE ecosystem Mandrel & Graal VM
  55. @elderjava 55 More demos

  56. @elderjava 56 developers.redhat.com/register

  57. @elderjava 57 Thank you!