18 ms·
Using Java 9 Modularization to Ship Zero-Dependency Apps
- Ecco 9y agoI love how the article shows an 11 MB Hello World as "stripped down" 2x improvement :-)
- nine_k 9y agoThe VM + minimal stdlib is not exactly small. Also AFAICT it works the same on every major platform, that is, it's a fat binary. Not bad.
- kevin_thibedeau 9y ago> Not bad. Unless you consider that basic support services are what the Java runtime should be providing on its own. Fundamentally, a command line Hello world should only take a few dozen bytes of bytecode.
- oblio 9y agoDoesn't this bundle the VM/GC/etc. besides the bytecode?
- paulddraper 9y agoYes, it does.
- kbsletten 9y agoThe 11MB is (most likely) 11MB of the Java runtime (compared to 200MB for the full runtime which includes all the classes required by the standard library) + a few dozen bytes of bytecode.
- zten 9y agoPlus, you can strip down the Java bytecode even further using ProGuard, but convincing it to not delete code that's actually used is an error-prone dark art.
- kodablah 9y agoI've been hoping that a community project would come about to break java.base into smaller modules. Even if there are cross/circular dependencies, I wouldn't mind if many methods were stubbed out or just removed if I promised not to use them.
- cytzol 9y agoYes, you can get smaller binaries using compile-to-native languages. But speaking as someone who had to install the JVM and our application on clients' computers, this is way better! You don't need to be the best to be good.
- karussell 9y agoThere is stuff in the works (heard this related to Graal I think) where Java will be a compile-to-native language.
- dullgiulio 9y agoAnd like the real Graal, it existed and got lost: it was called GCJ, part of GCC.
- wst_ 9y agoKotlin and Scala native are on the horizon.
- pault 9y agoStill better than electron.
- malkia 9y agoWe've been counting the number of apps that use Electron at work (Windows machines) - ok, Microsoft Teams, Visual Studio Code, Slack, and few others! Now all engineers are "angry" :) :) :) after seeing the same process spawned multiple times, and taking lots of gigabytes!!! (hehee)... I simply don't care and love the Slack app! (Teams is also nice looking, and Visual Studio Code rocks)
- lomnakkus 9y agoWell, I mean on my Arch Linux system libc is ~2M, so that's not exactly trivial either. The only reason hello world can be so small is that all the stdlib code already exists on your system -- not so for Java[1]. Of course there are far smaller libc implementations, but they may be missing functionality. [1] Unless, of course you require an installation of Java... which would kind of go against the premise of this whole exercise.
- blueline 9y agounless you're statically linking the entire standard library, libc being 2M is irrelevant, no? you only pay for what you use if you dynamically link it.
- fgonzag 9y agoso if the jvm is installed in your system, 11M out of the 11M in the example (since it includes the cut down jvm) is irrelevant? Then all you need for the example is a 1k .class file.
- mitchty 9y agoErr, glibc is its own level of derp. Here, a fully static binary on linux with musl libc, designed for static linking unlike glibc. Note, this on 32 bit arm, size might differ on different arches, all I have access to off the cuff: # printf '#include <stdio.h>\n int main(int argc, char**argv) { puts("hi"); }' > /tmp/hi.c # make /tmp/hi cc -c -o /tmp/hi.o /tmp/hi.c cc /tmp/hi.o -o /tmp/hi # du -hs /tmp/hi 12.0K /tmp/hi # ldd /tmp/hi /lib/ld-musl-armhf.so.1 (0x7f5af000) libc.musl-armhf.so.1 => /lib/ld-musl-armhf.so.1 (0x7f5af000) # strip /tmp/hi # du -hs /tmp/hi 8.0K /tmp/hi # rm /tmp/hi # make LDFLAGS=-static /tmp/hi cc -static /tmp/hi.o -o /tmp/hi # du -hs /tmp/hi 92.0K /tmp/hi # ldd /tmp/hi ldd (0x7f5e3000) # file /tmp/hi /tmp/hi: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, with debug_info, not stripped ungh, go home ldd and file, you're both drunk and dead to me right now: # objdump -p /tmp/hi /tmp/hi: file format elf32-littlearm Program Header: LOAD off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**16 filesz 0x00001f68 memsz 0x00001f68 flags r-x LOAD off 0x00002ea4 vaddr 0x00012ea4 paddr 0x00012ea4 align 2**16 filesz 0x00000204 memsz 0x00000798 flags rw- DYNAMIC off 0x00002eb4 vaddr 0x00012eb4 paddr 0x00012eb4 align 2**2 filesz 0x000000e0 memsz 0x000000e0 flags rw- STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4 filesz 0x00000000 memsz 0x00000000 flags rw- RELRO off 0x00002ea4 vaddr 0x00012ea4 paddr 0x00012ea4 align 2**0 filesz 0x0000015c memsz 0x0000015c flags r-- Dynamic Section: SYMBOLIC 0x00000000 INIT 0x00000468 FINI 0x00001f38 INIT_ARRAY 0x00012ea4 INIT_ARRAYSZ 0x00000004 FINI_ARRAY 0x00012ea8 FINI_ARRAYSZ 0x00000004 GNU_HASH 0x000000d4 STRTAB 0x00000250 SYMTAB 0x00000120 STRSZ 0x000000ee SYMENT 0x00000010 DEBUG 0x00000000 PLTGOT 0x00012f94 PLTRELSZ 0x00000018 PLTREL 0x00000011 JMPREL 0x00000450 REL 0x00000340 RELSZ 0x00000110 RELENT 0x00000008 BIND_NOW 0x00000000 FLAGS_1 0x08000001 RELCOUNT 0x0000001c private flags = 5000400: [Version5 EABI] [hard-float ABI] Note no NEEDED section, so we're indeed fully static. # strip /tmp/hi # du -hs /tmp/hi 16.0K /tmp/hi 16K for a fully static hello world sounds pretty decent to me vs 8k for dynamic. Will be faster than involving ld.so as well. I could probably improve that further, but I'm not about to golf this tonight.
- userbinator 9y agoAt the far end of the scale, here is a 20 bytes Hello World, nearly 6 orders of magnitude smaller: https://www.gnostice.com/nl_article.asp?id=225 https://www.gnostice.com/nl_article.asp?id=225 The difference in abstraction level is amazing.
- adamzegelin 9y agoDunno if I'd call Java native. This is more like zero-dependecy Java apps — aka, you don't need to pre-install the JVM (and its "optional" adware on Windows).
- SwellJoe 9y agoDoes that mean Go apps aren't native since they also have a runtime embedded? What defines "native"?
- chrisseaton 9y ago> What defines "native"? I think it's reasonable to say that if the the user code is transmitted as a managed intermediate representation then it's not native. Arguing beyond that probably isn't productive. But that's this particular blog post. Java can be native, if you compiled all the user code to machine code ahead of time.
- saghm 9y agoIf the VM is shipped as native code and the app is bundled with it as "code" that runs on the VM, is that fundamentally different from shipping an app written in compiled-to-machine code that bundles some data (JSON, XML, a SQLite database, etc.)? It definitely "feels" different, but I'm not convinced that the former is not "native" just because more of the logic is in the data rather than the machine code.
- SwellJoe 9y agoSo, anything that uses a JIT, such as the LLVM JIT, is not "native"? Are programs written in C# not native, even on Windows? Are programs in Java for Android not native, even though it is the language much of the OS is written in and what the standard UI toolkit is built for? Seems like lots of projects are likely to become non-native over time, by this definition, even if they start out "native" with a basic C/C++ codebase, since lots of projects accrete some sort of scripting or extension interface that might use a runtime of some sort. Is Emacs not native? Does it really matter if the runtime (which is machine code) was made by the compiler developer or by the application developer in some cases? I feel like there's an arbitrary line, and it's not entirely useful distinction to make. A native app can be big and slow and ugly and fail to follow the OS UI guideliness. An app with a runtime can be small(ish) and fast and beautiful and strictly adhere to the UI guidelines for the OS in question. I want the small, fast, beautiful, app with standard UI behavior, no matter whether it's delivered with a runtime embedded or built from C/C++ (and a few others) and without a JIT. I mean, we're just arguing semantics here, which is kinda silly. I think it's pretty neat; I don't really like working in Java, but I'd rather work in Java than C/C++, so if I needed to deliver a cross-platform GUI app, I'd certainly consider it.
- LoSboccacc 9y agobut why gradle?
- emsy 9y agoThis comment adds nothing unless you name specific criticism or ideas for improvement.
- yarrel 9y agoThat answer does not explain the choice of technology.
- emsy 9y agoI'm not obliged to. I just wanted to help the previous commentator out because I knew this would earn them negative karma for what could be a constructive discussion.
- LoSboccacc 9y agowhat a shitty community this has become, one can't even be curious now, it's just onanism about who's got the biggest breeeeinis
- drchickensalad 9y agoI'm pretty sure you would have gotten replies if it was just worded "Does anybody know any possible benefits of using gradle here?" or the like. I don't think it's much more than that.
- Groxx 9y agoThat would also significantly narrow the scope of the question to something that's actually answerable. "but why gradle?" is basically impossible to decide between "are there advantages to using gradle here", "gradle is abjectly terrible, why are you even using it", "gradle isn't available when compiling on an android device, why don't you use something with better platform support" or any number of more/less extreme/trollish questions/"questions".
- jcdavis 9y agoIs worth mentioning that SubstrateVM (https://github.com/graalvm/graal/tree/master/substratevm https://github.com/graalvm/graal/tree/master/substratevm) is now open source, which does whole-world AOT compilation to produce a single executable or shared library. It does have substantial limitations (eg no runtime class generation/loading), so it might not be suitable for every project
- ksec 9y agoHold on a sec? When did this happen? No Announcement? No HN submission? I still remember a Oracle JRuby / Truffle Ruby developer said Orcale has no plan to open source SubstrateVM. This is Great News! Edit: https://news.ycombinator.com/item?id=13653239 https://news.ycombinator.com/item?id=13653239
- mintplant 9y agoIt's ashame there's no Windows support, unless I've missed something.
- pjmlp 9y agoFor the time being. The plan is to support all major OpenJDK platforms. There is also Project Metropolis, which was recently started, with the long term goal of rewriting all existing C++ code into Java, so AOT needs to exist in all platforms.
- nine_k 9y agoNow combine it with JavaFX and we can have reasonably-sized cross-platform GUI apps again. Yes, you can compile a QT or a GTK app for every platform, and use e.g. Python or Go to write the cross-platform part + package it into a single file. It's still as many files as you have platforms.
- oblio 9y agoIt is interesting, but I wonder if it's not 10 years too late. Sometimes I feel Sun's dogmatism stopped them from taking over HTML5's role.
- criddell 9y agoDo you really think size matters? Does JavaFX actually feel native on all the supported platforms? Qt and GTK usually don't.
- nine_k 9y agoThere is a large niche for utility GUI programs that don't usually get a lot of UI polish or native feel. As long as they don't break general conventions and muscle memory, the users are OK with that. I suppose that JavaFX is comparable to Qt, and feels better than Tk or AWT, let alone a hastily-built web-based UI. I see e.g. my wife, not an IT person, use a number of them. An eBay betting app, several utilities for bead art, etc, most written in Java years ago. Do they look polished and native? Hell no. Do they get the job done? They do. Could they look and feel better with a JavaFX UI? Quite likely. Would having a single binary to download, without installing a JRE first, improve their adoption rates? Quite likely again.
- cpburns2009 9y agoHow easy is it to get a native look and feel with JavaFX on the various desktop OSes? That is, Windows, Mac, and Linux (GTK and Qt)?
- fian 9y agoWhy do you think you need native look and feel? I have worked on a Java desktop app with Swing UI for over a decade. Mid 2000s we would get asked to "modernise" our applications UI, which really meant: "make it look like Windows XP". After Apple released iTunes, which totally ignored the native look and feel on Windows, people stopped caring so much as long as it looked ok and was intuitive. The boom in web apps with every SPA defining it own internal LAF through CSS and Javascript and the fad for flat UI components seems to have further watered down the arguments for conforming to a native LAF. I haven't played much yet with JavaFX so can't answer your actual question but I believe it is more flexible than Swing and Swing is already very customisable (though you sometimes need to create your own widgets by extending/implmenting off the default widgets).
- digitalsanctum 9y agoI've recently become much more interested in Kotlin to provide true native apps. The trade-off is that the native bits are still pretty green.
- kodablah 9y agoAnd the GC and the minimal stdlib and other things. If you are targeting multiplatform, Kotlin may be a reasonable choice so long as you don't need anything advanced the JRE provides (or are willing to abstract it and have a native equiv also). Otherwise, there are too many native options these days to use Kotlin solely for that purpose IMO.
- malkia 9y agoThis would be great for BUILD tools like bazel which is written in Java.
- mkobit 9y agoDo you mean for Bazel itself or for building apps with bazel? Bazel is still a bit away from having Java 9 support [1] and it still requires some system dependencies (for the other languages and cross system support). I wish more tools would go the "static binary" path that make it easy to build and use wrappers without having to figure out system configuration every single time. [1] https://github.com/bazelbuild/bazel/issues/3410 https://github.com/bazelbuild/bazel/issues/3410
- malkia 9y agobazel itself. One of the complaints I here (not sure how valid they are) is that people's docker images tend to grow a lot, and I'm not proposing bazel yet, as it'll pull additional hundreths of megabytes, plus some more per WORKSPACE. For Windows, it's mainly perception - if engineer sees that a tool is like 200mb in the depot, he/she be like - that's too much :) "Remember why we pulled boost, and no longer use it - as it's huuuge!" :)
- freedomben 9y agoThis is definitely an improvement for Java, but it leaves me with a few thoughts as someone who has done Java professionally at times, but also professionally lived in other ecosystems including C++/Qt, Python, Ruby, Golang, and of course node/JS. 1. Setting up a project is still a pain in the butt. Tools like Gradle are a nice improvement over Ant (and some would say maven), but still most people don't even understand them. You have some serious reading ahead of you if you want to set something up that isn't already templated somewhere for you. You can lean on an IDE for sure, and for most Java devs this is probably a no-brainer. I'm weird in that I don't like magic. I prefer to know what the tool is doing on my behalf, and the Java IDE world is so complex that it isn't practical to learn that unless you're in the ecosystem for years. Then dealing with weird exceptions from the JVM can be maddening. 2. The Java world moves slowly. It could reasonably be years before many shops transition to Java 9, when you would actually realize the benefits of this in your work life. 3. So much Java runs on the server side anyway, where executable size and entrypoint doesn't really matter that much. Because of this, it may only be a small subset of Java shops that really get into Java 9/Jigsaw and iron out the bugs, and create tools/tutorials for others.
- malkia 9y agoCurrently I'm doing C++ with Qt, sometimes C# (game dev under Windows), but was at Google just few months ago doing Java. While Qt is great, we've been running into logistic problems - like we have plenty of tools that use it, and we are forced to place all the binaries into one folder ("bin"), and the Qt dlls there for legal reasons, license, but buying the license for static linking won't be a problem for us reallly. The real problem is that once we link our binaries statically, then our plugins that also use Qt won't work with them, unless we do some magic, and forward all QtXxx.dll end points to be from the main executable, or use more abstract interfaces - e.g. our plugins should not use Qt directly.
- kodablah 9y agoI likewise have used these. Qt (really C++) development in general suffers from annoyingly slow compile times in my experience. Also, once you go beyond anything trivial, .pro files become complicated as do build systems around them.
- malkia 9y agoHow are .so, .dll files handled during Java packing? This is more open question, but say you have one ".exe" file. Now you need to extract the DLL in a place, and make sure everytime it's the right one (gets tricky if the tool is ran simualtnenously, like spawned from a build process). While I was at Google, instead of having multiple .so files, the main launcher was a C++ binary, and all external C++ dependencies were linked into it (that's it if you have the source code), then you didn't need that. I guess now it's up to the BUILD system to achieve that, where if you have more flexible BUILD language you can instruct everything to go in the main launcher file, then have all the .jars into one, slapped at the end of the file. At the end, ship or update only one binary to your service, desktop machine, etc.
- zten 9y ago> How are .so, .dll files handled during Java packing? Native libraries used by JNI can be shipped in the jar files and are read from the classpath, in addition to reading them from the ordinary linker path. (edit: turns out I'm wrong about this on Windows)
- malkia 9y agoBut on Windows you must "extract" and copy the DLL file somewhere (ok, possibly you might be able to do in-memory load, but that is very non-standard and might trigger antiviruses). I think the same is with the Python packagers, or C# shadow copy.
- weej 9y agoYou need to package up the JAR with the shared object / dll and install both on the local filesystem in order for the SO to be accessible from the classpath. For example you could apply a package manager (RPM) and include the JAR and .so at install for available use.
- malkia 9y agoBut if you were able to "contain" all the source code from your DLL into your main "java.exe" launcher, and then slap the all the .jars at the end of the "java.exe" and then renamed it to "mycoolapp.exe" then it might be just that... off course if licensing agrees with you, and you have the source code, and want to deal recompiling these like that... also compiling it along with the java launcher. This way there is no need for extra install, uninstall. Possibly too much over-engineering for full blown product, but if it's something that needs to be run, and updated on tons of machine - not having to deal with extra artifacts might be a win.
- iamleppert 9y ago"and superior to web-hybrid options like Electron" Superior exactly in what way? Electron allows access to an enormous audience of developers and the web ecosystem. You really can't compete with that and would be silly to try at this point.
- Negitivefrags 9y agoYou cut out the rest of the sentence which was specifically referring to on-disk size.
- iamleppert 9y agoIt's not valid (or even remotely tangential) to compare a hello world app with minimal GUI to a full web browser.
- kodablah 9y agoHow about comparing a hello world app to another hello world app? Or do you consider that comparison invalid because Electron/Chromium don't have ways to strip unused features? To me, a comparison of similar end results is reasonable. Arguments about whether hello world apps represent reality, or comparisons between WebGL/WebAudio apps vs LWJGL apps, would be more apt.
- kuschku 9y agoThe Java standard libraries also contain a full web browser, and much more than what your browser can do.
- dullgiulio 9y agoThe author misses the point when he says this might help Java regain share in the space of DevOps tools which is currently mostly Go. The problem is not artifact size but the JVM slow start-up time. This is made worse by almost all Java frameworks that by definition do all their own stuff before passing control to your real app code. Such executables are not something you would put in a loop in a shell one liner, and that is the space for command line utilities Go has occupied successfully.
- twic 9y agoThe JVM doesn't suffer from slow start-up time: https://purelyfunctional.tv/article/the-legend-of-long-jvm-startup-times/ https://purelyfunctional.tv/article/the-legend-of-long-jvm-s... But frameworks (and runtimes for things like Clojure) absolutely do. It would be possible to write a fast-starting framework for Java, but i suspect nobody has because there's no demand for it, because nobody who needs fast startup uses Java, because it doesn't start up fast! That said, i think the real reasons Go has done so well in devops are (1) it's easy to pick up for devopsists coming from Perl/Ruby/etc backgrounds, (2) static binaries are easier to deploy than a jar plus a JVM (not massively easier - but easier enough), (3) a focus on systemsy stuff in the standard library and community, and (4) sheer snowballing momentum, in that Go has become the default choice for stuff like that.
- deleted 9y ago[deleted]
- userbinator 9y agoThat's actually pretty fast. Starting the JVM, grabbing the memory for the heap, and then exiting takes one tenth of a second. Things like this are why all the "Java isn't slow" articles miss the point completely --- 100ms to do nothing useful, on a presumably quite fast machine, is ridiculous. For comparison, 100ms is roughly the time it takes to grep an 18MB file: http://dtrace.org/blogs/brendan/2011/12/08/2000x-performance-win/ http://dtrace.org/blogs/brendan/2011/12/08/2000x-performance... (look near bottom of post).
- alfanick 9y ago> Using Java 9 Modularization to Ship Zero-Dependency Native Apps > [...] > and superior to web-hybrid options like Electron How is Java or Electron (JavaScript+WebKit) considered native nowadays? Please use native APIs, so my laptop can actually hold 10h load on battery. edit: can we remove native from the title?
- dang 9y agoWe'll take 'native' out of the title to reduce arguments about 'native'.
- kuschku 9y agoJava can be compiled to a native binary now, thanks to Java 9. No bytecode, interpreter, or JIT left in the resulting file. (Only available for Linux x86_64 right now).
- readittwice 9y agoIf you are talking about Java's AOT feature (JEP 295: http://openjdk.java.net/jeps/295 http://openjdk.java.net/jeps/295) then I don't think it is true AFAICS. The JVM is still needed, Java-Code can be compiled into a shared library but this is "just" a code-cache that can be passed to the JVM when starting the application. This feature is mainly aimed for improving startup.
- kuschku 9y agoI’ll link you the beautiful thing I’m referring to: https://github.com/graalvm/graal/tree/master/substratevm https://github.com/graalvm/graal/tree/master/substratevm
- readittwice 9y agoAh thanks, I got confused because you mentioned Java 9. I really hope Substrate VM or something similar gets into the JDK. Having the option of AOT-compilation or using jlink for bundling would be amazing.
- sillysaurus3 9y agoAnyone notice that Java is suddenly cool thanks to Kotlin? I haven't done much more than dabble, but it was an enjoyable dabble. Unlike vanilla Java. It even compiles to JS with a relatively small-ish runtime. It's big enough to cause problems embedding it, but it's small enough to be workable. https://github.com/JetBrains/create-react-kotlin-app https://github.com/JetBrains/create-react-kotlin-app
- drraid0 9y agoAre the installers for such "native" apps going to ask me to install an Ask.com toolbar?
- stevefan1999 9y agoI reckon Mono had offered the same thing, although it bundles the entire mscorlib...
- fulafel 9y agoDoes this affect Clojure? If so, how?
- marmaduke 9y agoFor the purposes of this article, Clojure is "just" a library to process text, generate & run JVM byte code, and the workflow could be applied to a Clojure project. The AOT compiling though would require Clojure-AOT followed by JVM-AOT I guess.
- e12e 9y agoPrevious discussion: https://news.ycombinator.com/item?id=15521611 https://news.ycombinator.com/item?id=15521611
- venomsnake 9y agoLets hope this kills the travesty of dependency injection.