Multiple Java VMs on OSX
Multiple Java VM on OSX
Introduction
Let’s start by reviewing the baroque installation of Java on OSX.
Try these (highlighted) commands in a terminal.
1 2 3 4 5 |
$ which java /usr/bin/java $ ls -l /usr/bin/java lrwxr-xr-x 1 root wheel 74 Sep 30 21:18 /usr/bin/java -> /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java |
So, when you install Java, /usr/bin/java is the vm command. It’s a symbolic link to the “current version”.
In my case Current is a symlink to a directory named A.
1 2 3 4 5 6 7 8 9 10 11 |
$ ls -l /System/Library/Frameworks/JavaVM.framework/Versions total 32 lrwxr-xr-x 1 root wheel 10 Sep 30 21:18 1.4 -> CurrentJDK lrwxr-xr-x 1 root wheel 10 Sep 30 21:18 1.4.2 -> CurrentJDK lrwxr-xr-x 1 root wheel 10 Sep 30 21:18 1.5 -> CurrentJDK lrwxr-xr-x 1 root wheel 10 Sep 30 21:18 1.5.0 -> CurrentJDK lrwxr-xr-x 1 root wheel 10 Sep 30 21:18 1.6 -> CurrentJDK lrwxr-xr-x 1 root wheel 10 Sep 30 21:18 1.6.0 -> CurrentJDK drwxr-xr-x 10 root wheel 340 Nov 9 08:01 A lrwxr-xr-x 1 root wheel 1 Sep 30 21:18 Current -> A lrwxr-xr-x 1 root wheel 52 Sep 30 21:18 CurrentJDK -> /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents |
A lot of “legacy” links in there. Right now, “Current” is the one we care about.
Let’s see what version your current default vm happens to be:
1 2 3 4 |
$ /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java -version java version "9-ea" Java(TM) SE Runtime Environment (build 9-ea+96-2015-12-10-032020.javare.4030.nc) Java HotSpot(TM) 64-Bit Server VM (build 9-ea+96-2015-12-10-032020.javare.4030.nc, mixed mode) |
If you simply run java -version (no path), you get the same output.
1 2 3 4 |
$java -version java version "9-ea" Java(TM) SE Runtime Environment (build 9-ea+96-2015-12-10-032020.javare.4030.nc) Java HotSpot(TM) 64-Bit Server VM (build 9-ea+96-2015-12-10-032020.javare.4030.nc, mixed mode) |
In my case, I installed the OpenJDK preview of Java 9.
But wait. In the directory listing for /System/Library/Frameworks/JavaVM.framework/Versions there was no Java 9. Where are the 1.7+ VMs?
You can use /usr/libexec/java_home to find the names of your installed VMs.
1 2 3 4 5 6 7 8 9 10 11 12 |
/usr/libexec/java_home -V Matching Java Virtual Machines (8): 9, x86_64: "Java SE 9-ea" /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home 1.8.0, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home 1.7.0_51, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home 1.7.0_17, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home 1.7.0_12, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_12.jdk/Contents/Home 1.7.0_04, x86_64: "OpenJDK 7" /Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home 1.6.0_65-b14-468, x86_64: "Java SE 6" /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home 1.6.0_65-b14-468, i386: "Java SE 6" /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home |
So, the “newer” i.e. current VMs are in /Library/Java/JavaVirtualMachines.
That last line shows your current “default” VM. Run java_home with no arguments to verify.
1 2 |
$ /usr/libexec/java_home /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home |
OK. So what?
Let’s see what java_home with the -v (lower case v this time) flag and a VM version gives us.
(use the vm name in /Library/Java/JavaVirtualMachines without the jdk prefix)
1 2 3 4 5 6 |
$ /usr/libexec/java_home -v 1.6 /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home $ /usr/libexec/java_home -v 1.7 /Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home $ /usr/libexec/java_home -v 1.8 /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home |
So, this gives us the full path to the installed VMs.
What about Java 9? Well, OpenJDK’s Java 9 uses a different naming convention, so you simply use 9 as the version.
1 2 3 4 5 |
$ /usr/libexec/java_home -v 1.9 Unable to find any JVMs matching version "1.9". /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home $ /usr/libexec/java_home -v 9 /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home |
This is a way to set your environment variables in your shell login config file (.e.g. ~/.bash_profile, NB not .bashrc).
1 2 |
export JAVA_HOME=`/usr/libexec/java_home -v 9` export PATH=$JAVA_HOME/bin:$PATH |
Of course, if you want to change your VM “on the fly”, you’ll have to remove the old VM path from PATH. Unfortunately, even with Bash you have to engage in some sed nonsense. If you know an easier way (than sed), let me know.
So, cool. In the terminal, you get the VM you want. What about things that aren’t run from the terminal. Like an IDE? If you run Eclipse with the current snapshot of Java 9, it will crash. Setting your environment variables in .bash_profile does not affect these launches.
Eclipse
If you have Java 9 installed, you won’t be able to run Eclipse. The solution is to edit Eclipse’s config file to use a specific VM. Here is mine. I added the lines -vm and the path to Java 1.8.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
$ cat /Applications/Eclipse\ Mars/Eclipse.app/Contents/Eclipse/eclipse.ini -startup ../Eclipse/plugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar --launcher.library ../Eclipse/plugins/org.eclipse.equinox.launcher.cocoa.macosx.x86_64_1.1.300.v20150602-1417 -product org.eclipse.epp.package.jee.product --launcher.defaultAction openFile -showsplash org.eclipse.platform --launcher.XXMaxPermSize 256m --launcher.defaultAction openFile --launcher.appendVmargs -vm /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/bin -vmargs -Dosgi.requiredJavaVersion=1.7 -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts -XX:MaxPermSize=256m -Xms256m -Xmx1024m -Xdock:icon=../Resources/Eclipse.icns -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts |
Global variables
How do you set environment variables globally on OSX?
The current way (in El Capitan) is to create a plist in ~/Library/LaunchAgents/ that will be read by launchctl. In older versions of OSX, you edited /etc/launchd.conf
Eclipse seems to ignore these variables though. The eclipse.ini trick works.
Summary
Java on OSX is a bit of a mess.