* Only 64bit Linux on AMD64 is supported, so no ARM or Android support currently.
* Files must be ran on computers they were compiled on, or identical hardware
* Still needs GC, only G1 and Parallel GC are supported
* No dynamic byte code (Lambda Expressions, Dynamic Classes, etc.)
* The only supported module is java.base
* No decrease to JVM start up times
* Still need the JVM
* Some decrease to spin up as there will be less JIT passes that require stopping the world.
Effectively this just lets you pre-load .class files into the codecache directly rather then running the ~10k initial byte-code passes before they'd receive a JIT pass and that would happen.
Lastly .so is just used as a container so I doubt we can expect to dynamically link against AOT compiled Java in C/C++/Rust land.
> No dynamic byte code (Lambda Expressions, Dynamic Classes, etc.)
That just means it won't be AOT compiled. The JVM can still JIT them.
> No decrease to JVM start up times
The JVM itself starts quite fast. Most of the time spent in startup comes from the applications themselves. Spend a lot of time in the interpreter running their startup code and burning CPU cycles on the lower compiler tiers.
> The only supported module is java.base
Supported in the sense of oracle offering support. You can still compile other modules. It's just experimental.
"Non-tiered AOT compiled code behaves similarly to statically compiled C++ code, in that no profiling information is collected and no JIT recompilations will happen."
My question is how much memory can be saved by not having the JIT. Sure you still have a GC with a heap (VM) but one of the big pigs in memory can be the JIT.
This is an interesting question. The JVM CodeCache is normally rather small 24MB-48MB. But the JIT and all of its IR/Branch tracking? I Imagine non-trivial.
Since we have significantly more RAM to spare than a few years ago and caching, almost by definition, is nothing but trading memory for cpu cycles. You want less memory? No problem, just remove the cache and recompute everything all the time, but don't cry if it takes time.
If 24-48MB is trivial completely depends on what is stored in this space, i.e. is there a more efficient representation for your stated goals? Context is king. Even 5MB could be non-trivial, depending on context.
$ java -version
openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-0ubuntu4~14.04-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)
$ java -Xmx999k
Error occurred during initialization of VM
Too small initial heap
Rather since we have multi-gig RAM on consumer machines.
On embedded systems it might not be trivial, but on my laptop with its 4gigs of RAM and even more so on my desktop with 16gigs, 50mbs is definitely trivial.
> Only 64bit Linux on AMD64 is supported, so no ARM or Android support currently.
Do you know what you are talking about ? Android is totally different thing than JVM and Java Ecosystem ! It is totally different technology ! They use one step to turn your bytecode to their own dex file, after that it is completely separated from Java ecosystem (Java as ecosystem which comes from Oracle).
I am fascinated on HN, how comment uneducated like this, haven't got down voted.
They use kind of hybrid AOT/JIT right now. (It was interpreter until 2.2, they switched to JIT, in android 5 they switched to complete AOT, now they are going kinda hybrid approach).
This is clearly still great for a few places. For example in the trading industry, you would have a few seconds of being very slow when starting up for the week - or anytime you crashed and needed to reboot midweek.
Also risk of "hot pathing" the wrong paths if the server comes up during say a market closed time...
Exactly. There are a lot of high performance system written in Java. For long running systems, the startup cost is irrelevant. And for networked systems (such as fintech) you are going to be IO bound. The main issue as far as Java and high performance is the GC related pauses and that is a concern shared with any GC'd runtime.
And for Java it's actually much less of an issue thanks to the crazy manhours put into developing fast GC for Java. I suspect Azul Systems's pauseless GC is probably quite popular in HFT.
You're assuming Java is slow. Evidence suggests otherwise. Eg. LMAX Exchange uses a lock-free ringbuffer they call Disruptor [1] which enables 6M tps on a single thread [2]
I seem to recall a prior discussion where a dev working on HFT stuff said that speed is a huge factor, but so is the ability to rapidly change functionality. They settled on Java because it was fast enough (HFT would have to be IO bound, right?) while still being flexible enough to allow them to adapt to daily changes in requirements.
Besides what the others already replied, the use in the trade industry is one of the reasons of Java having to adopt AOT, value types, JNI replacement and better integration with GPGPUs.
I have done this so can confirm, but every time I did I wished I didn't need to. I had a running nightmare where yesterday's trading data made us trade today.
Might not even be that. At some point you need to cut out the output from going to the real exchange.
If you had an IF somewhere random in your code.. you will then JIT code that is wrongly optimized.
If you try to put some kind of network device to capture the traffic and respond with fake responses to make the code happy.. you are one bitflip away from sending bad stuff to prod.
Except at the exchange, where you can't do this. Or you accidentally bitflip something and take yesterdays data, inject into todays books, and cause millions of dollars in mistakes.
Sorry, if you are reading it as "no big accomplishment", yeah, not right.
My question is really "why will it succeed this time?" Did GCJ and similar technologies not take off because Sun didn't support them? Or because it is a really neat technical challenge that solves a problem people don't actually care about?
So, yes, this is cool. But, I'm currently giving it a likelihood of success really low, since I have priors that failed. What other evidence are people seeing that make this something to be excited about, as opposed to just impressed. (Or, are we just impressed and I can go back to my corner?)
Almost all commercial JDKs support AOT to native code.
Sun was religious against it.
Regarding the GCJ, it failed because it is a hard problem where people didn't work for free and most of them stopped working on it when the OpenJDK was released.
Unfortunately no, I am aware of them, because as language geek I like to research these subjects.
While others read newspapers on the train, I read papers. :)
In any case, these provide AOT.
JamaicaVM, PTC Perc (former Atego and Aonix), IBM J9, Oracle Embedded Java, OS/400 Java (uses the same bytecode deployment as the other OS/400 languages), Excelsior JET, and probably a few others in embedded market that I am not aware of.
Awesome, thanks for responding. I have the same hobby of reading up on this sort of stuff, so I knew of quite a few of those. Just don't know of much for a use case of them.
I think the big distinguishing feature is that this is first-class support built into the platform, so it will likely have many more users than previous efforts. I don't anticipate it being generally useful until at least JDK11, though.
The great language convergence is happening! It seems like everyone is moving to expressive statically typed, compiled, functional, oop languages. Not that I'm complaining.
This means that we might actually get a language that becomes the new c in terms of popularity.
I look at this as cyclic trends (I'm not sure if 'trend' is the right word here, but it's a good enough approximation) - as you've said, we're entering the cycle of 'expressive statically typed, compiled, functional' (not sure about oop), but soon the cycle will go back to the dynamic languages, because they are "faster when iterating on product" etc. But who knows, maybe we'll stay in current cycle forever? ;)
I don't think so, well, at least not entirely. :-)
Dynamic languages were attractive as an alternative to being forced to specify types all the time, even when it's "obvious." Nobody would have complained if type errors were pointed out for "free."
But type inference is getting popular (eg scala), which is showing people that you can have your cake and eat most of it too.
There's also a lot of little things like REPLs, runtime metaprogramming, blah blah, that used to be solely the domain of dynamic languages, but popular interpreters/VMs have gotten way better in the last decade or two (thanks, JVM) and shown that you actually _can_ have it all. There's no longer a big strong line between interpreted and compiled.
If you can make a statically typed language expressive and fast-to-iterate enough, which I think you can and we (mostly) have, then that kind of yanks the ground right out from under the feet of the dynamic languages, leaving them with no real reason to exist in the long run.
That said, there's something attractive to the unexperienced about being able to code in the laziest possible way, and I don't think platforms that deliver a tiny bit of value in the short run in exchange for massive payback in the long run will ever lose popularity, among new engineers who have not yet learned what it's like to maintain a large program. There will always be PHPs as long as there are students. And that's OK. You learn to do thing well by doing things poorly. But hopefully over time such tools will mainly be used for trivial and learning projects, not big mission critical things
> There's also a lot of little things like REPLs, runtime metaprogramming, blah blah, that used to be solely the domain of dynamic languages
If you go read the Xerox PARC, DEC and ETHZ papers you will find REPL goodies using static system programming languages with automatic memory management.
The Xerox ones even did correction suggestions when compiler errors happened.
Namely Mesa/Cedar, Modula-2+, Modula-3, Oberon and its descendants.
I've been thinking about type inference in this context but I don't think that's enough to convert people to static languages. I agree that there is a general problem with the 'laziest possible way' to program as you put it - dynamic languages are way more forgiving that static ones. And while tools may evolve to make some things trivial, I think that there (almost) always be some areas where dynamic languages' forgiveness will be good enough reason for some people to use them. Today these are types but in the future there'll be something else to sacrifice.
The theory of statically typed languages[1] is progressing while "dynamic" languages haven't actually had many real advances since e.g. Scheme[0] first appeared. Sure, there's small things around ergonomics, immutability (Clojure, especially), but really there's been very little true advancement[2].
Personally, I think either static (dependent) types will win[3] or we'll just end up implementing different custom static type systems ad-hoc[4]. My reason for having more confidence in the former rather than even more formal methods is that there are very few math-like/truly spec-level languages (e.g. TLA+) that can be mechanically translated to a meaningful program. We need something intermediate, but so far (to me!) Idris[5] has seemed like the only remotely credible contender in that you can pretty much choose arbitrarily how much provin' vs. how much assumin' you want to do.
EDIT: The current hype (in frontend especially) seems to be around 'gradually typed' languages like TS and Flow, but AFAICT they are basically just a very poor man's ad-hoc version of dependently typed languages. (Concretely TS/Flow do have a huge advantages in that it's really easy to introduce, but personally I had no problem transitioning gradually from ES6/traceur to Scala.Js/React just by adding strongly typed shims where appropriate. If your application is so tangled that you cannot introduce such shims in various places, it's probably tangled enough that you'll want to do a full rewrite anyway.)
[0] I think Scheme was the first to introduce first-class continuations. That was a pretty major advance in terms of expressing, for example, search algorithms by just rewinding to a previous continuation. Of course, since then "we"(Felleisen, specifically) discovered that delimited continuations are perhaps better -- but that was a 'refinement'.
[1] Aka: languages with more than one type.
[2] Of course, some might interpret (pun!) that as a sign that they're "perfect". However, we still get loads of bugs in dynamically typed languages, so surely there must be something to be improved upon, right?
I don't really see the cycle. I just see it as languages getting closer and closer to Lisp, as per usual. Turns out the static languages had a lot more growing up to do than the dynamic languages, so you're seeing 'big' changes like Java 7 through 9, C++0x through C++1y, new languages like Go, Rust, Nim, Scala... Meanwhile the only recent dynamic languages worth talking about are Clojure, and maybe Julia and Elixir. Across the field of dynamic languages though you see a little more movement to optional typing (and more powerful typing semantics like schema or protocol conformance or other things you can do with dependent types) and maybe some concurrency or JIT or AOT trinkets from other implementations that all boil down to performance improvements of some sort. The language design on the dynamic end has changed much less because they have less to change.
Yeah it's an extinction event in the evolutionary cycle of computing. Im not sure when was the last one.
I think that excessive dynamism is getting less attractive when you account for all the costs it brings with it and that the vast majority of the benefits can be achieved with static metaprogramming, in a more readable and safer manner.
Depends on how exactly how functional you want to go, but latest versions of C++, Java, JavaScript, and C# definitely qualify. Rust, too, though it's not strictly OO. And Python, Ruby, Swift.
If Rust is OO then the term is meaningless. No inheritance; dynamic dispatch only via explicit indirection (Boxed traits); methods are (therefore) just syntactic sugar for regular functions.
Common Lisp has inheritance of methods, but it does not work on a class hierarchy directly. When a generic function gets called, the applicable methods are being ordered based on the classes of the arguments - not just one argument, but possibly many. A more specific method can call the next method. In some cases this is done automatically. This is inheritance, based on the class hierarchy.
CLOS also allows the developer to implement other inheritance mechanisms, by developing his own way to combine the methods of a generic function.
Rust fails many of the other tests mentioned. As for polymorphism, is Haskell OO? If so, then I think my claim that the term is meaningless is justified.
CLOS effectively does have inheritance for methods because for sane specializers subclass matches everywhere where it's superclass matches. One can in fact view the CLOS mechanism of specializers and effective-method composition as more flexible mechanism for inheritance than traditional implementations of OOP.
All of these things are found in Haskell as well; it's not OO by any stretch of the imagination. You're confusing "oop language" with "modern programming language".
For the JVM experts here: how realistic is it for OpenJDK developers to add a command line "-useGreenThreads" option? In Golang, you can create thousands and thousands of threads and there's no issue. If I tried that in the JVM, it would quickly crash. But if there was a "-useGreenThreads" option, I could create Java Executor threadpool of size 50000, use existing http client libraries, and get full concurrency.
Quasar might be the closest in the meantime. One problem is that blocking IO blocks all the green threads (fibers). It might be possible for Oracle or someone to fix that by wrapping NIO with green threads to implement the IO APIs. Most people will just use async NIO wrapped in fibers so it appears synchronous. Also with Quasar any calls to Thread sleep, wait, or synchronization block all the threads. It would not be an easy feature for Oracle to add but Quasar has been attempting to get merged into the JRE. For Java 9 they said they got some features added that improves the situation but Quasar instrumentation will still be required.
The Quasar instrumentation in my opinion is a pain. Out of the box you either get AoT instrumentation or you use Java agent command line option. Both were problematic for me in context of build processes, IDE support, etc. It's possible to do runtime instrumentation with no special command line option using the Quasar URL classloader and Ant task which scans classes to instrument.
I probably shouldn't have used the term "green threads" since that has history in the JVM. I meant whatever Golang is doing which is similar (M:N threading). With an AOT option for Java, this becomes even more of an option. Golang has shown this works, why can't Java implement the same idea and let all existing libraries benefit from it?
Green Threading is M:N threading. Go-Routines are M:N threading. Q.E.D. M:N threading isn't a new idea. Go just offers a backed (or compiled) in run-time that does M:N threading by default for you.
While nearly every other Green Threaded language offered as an additional library/option. This hurt adoption. While Go just forces you to use Green Threading.
With an AOT option for Java, this becomes even more of an option.
Not in the slightest.
why can't Java implement the same idea and
let all existing libraries benefit from it?
A laundry list of reason:
1. Change what functions do and don't block can cause huge issues with down stream libraries/people who depend on system libraries behaving the same thing tomorrow as they did yesterday.
2. Refactoring all code around system calls so they never block.
3. Write a multi-core and multi-socket scheduler.
4. Write a scheduler to balance multi-core and multi-socket thread load.
5. Determine how you will do polling, and write a polling strategy to figure out what green threads are/are not blocked, then figure out how to communicate this information efficiently.
6. Repeat the above 5 steps for EVERY platform Java runs on.
There are problems with separating JVM and OS threads, mostly in assumptions that native library authors may have made about that mapping being 1:1. That isn't to say the situation can't be improved in specialised environments (see the JVM at Google talk at http://www.oracle.com/technetwork/java/javase/community/jlss...) but fixing it in general is a hard problem. It is being thought about though - see John Rose's talk at this year's JVMLS.
Because that's at the library level. It would require rewriting code to use it which loses one of the big advantages of the JVM (a huge existing ecosystem).
If it's at the JVM level (with a command line option to change how threading is done such as -useGreenThreads") then it's transparent to all existing code. I can just use anything (such as existing JDBC library), increase threadpool to levels that would be considered "ridiculous" with current JVM threading system, and it would all work fine. No code changes necessary for existing libraries.
Except I don't think you can just magically do that.
People do this in Python, but they do it in Python because
1) Python is dumb and has the GIL, much easier to hack in
2) They use reflection to change libraries, but it breaks anytime you would hit native C code. With Java trying to JIT everything, you are now having to change threading at the assembly level.
I think it is would be a ton of work to do at the base JVM level. If you look at the people behind the library I linked, it is many of the core Java people. They might have more insight on reasons why it won't work.
Green threads are very different from system threads. With green threads you get an illusion of concurrency, and when coding you need to account that multiple green threads work on a single system thread.
There's no way you would get a switch like that, because you interact with them differently. I wish greenthreads would not use "thread" in the name because it causes confusion like in your case.
Green threads and system threads are the same illusion to programmers (or, at least, they can be). The only caveat is that dependencies using system threads won't play nicely with green threaded code. Quasar, which does green threads for Java, schedules and distributes your green threads to system threads, one for each cpu. The Quasar API for green threads is basically identical to built in Java APIs.
Well a System with 16 CORE / 32 Hardware threads.. you run a program with 32 threads, you can legit run 32 things in parallel. Now not really because of OS scheduling and logs and other junk going on, but it could actually happen.
You take the same code and run it with 3000000 green threads... you are still capped out at 32 things running at the same time. Your system can kinda sorta pretend to be more concurrent, but the actually concurrency is the same.
This is very exciting, but still a long way from what people probably think it is at first glance.
This isn't "compile your application to an EXE", like Go or Rust. This is "compile some or all of your application to a DLL, and then have the Java runtime use that DLL".
In other words, you still need a JRE available. The use case for this is simply optimizing hotspots in some very specialized situations.
Not even compile to a DLL, really. The file format happens to be an ELF shared object, but its contents are unusable to anything other than Java, so it's effectively just a blob.
Some info for those that want to AOT Java without paying for it:
The entry-level edition of Excelsior JET is free (as in beer) since the end of August 2016. Licenses for the more senior editions have been available for non-commercial use at no cost for many years.
Hotspots aren't really going to be any faster with this change. The jvm already does a pretty good job of optimising hot code, which is why the vm is literally called hotspot.
AOT compilation is mostly intended to address startup time, Java has a big std library and much of it needs to be interpreted and compiled each time it runs.
Between jigsaw modules and this, we should see some nice improvements in startup time.
I don't think this is right, is it? I think this change is more about consistent performance than startup performance.
For me the JVM starts really quickly; the only performance issues I've seen there are related to large bloated frameworks doing too much at load time. I don't recall the std library being a factor at all (and why do you think it is recompiled every invocation?)
The JEP explains it pretty clearly.
"Improve the start-up time of both small and large Java applications, with at most a limited impact on peak performance."
This is very exciting! Question for the experts out there, do you think this has the potential to do away with using the JNI in new projects for the speed boost?
This change has nothing to do with JNI whatsoever.
The JVM has always (well, not always, but for 15+ years) run Java code by first compiling it to native code. The only difference is that the JVM will now allow you to optionally do the compilation ahead of time, in order to decrease an application's startup overhead. This actually hurts performance of the compiled methods, since runtime profiling is not available to the AOT compiler (but the document also describes a "tiered" mode, where AOT-compiled code can be dynamically replaced with a better JIT-compiled version at runtime).
If you want to link your Java code with native code written in a non-Java language, that's a totally different requirement, and JNI will continue to be the way to accomplish it.
Are there any that support the current class file format? ARM jazelle is no longer being worked on. So I would be surprised if there is anything that can do Java SE directly. JavaCard of course being quite different than standard Java.
Java bytecode is too highlevel for it to be suitable to run directly on hardware. Each instruction can map to multiple machine instructions. A JIT or AOT compiler can optimize the code on a lower level. A hardware implementation cannot do inlining, loop unrolling, hoist array length checks out of a loop, etc...
Look at class file sometime. It is basically bad C code in appearance. It is nowhere close to assembly type code, which is what the final output of the JIT is.
This probably does not affect android. In 5.0, android switched to AOT with a new VM, ART instead of Dalvik, which was a huge win for performance. Jitter in many, many apps went away completely, especially when scrolling. This did cause install times to increase, however. In 7.0 (or 7.1?) there is a mix of JIT with AOT for code that is deemed hot by a profiler, hopefully bringing the benefits of AOT without the lengthy install times.
Android and Oracle's Java have been diverged for quite a while. There aren't any Java 8 features available to Android now, so you sadly shouldn't hold your breath for any Java 9 features either, it will probably be a long, long time.
* Only 64bit Linux on AMD64 is supported, so no ARM or Android support currently.
* Files must be ran on computers they were compiled on, or identical hardware
* Still needs GC, only G1 and Parallel GC are supported
* No dynamic byte code (Lambda Expressions, Dynamic Classes, etc.)
* The only supported module is java.base
* No decrease to JVM start up times
* Still need the JVM
* Some decrease to spin up as there will be less JIT passes that require stopping the world.
Effectively this just lets you pre-load .class files into the codecache directly rather then running the ~10k initial byte-code passes before they'd receive a JIT pass and that would happen.
Lastly .so is just used as a container so I doubt we can expect to dynamically link against AOT compiled Java in C/C++/Rust land.