ChatGPT解决这个技术问题 Extra ChatGPT

如何更改从 /usr/libexec/java_home 返回的 Mac OS 的默认 Java VM

(不确定这是否应该继续 SU...迁移当然是一种选择,但更多的程序员在这里阅读问题,所以这里是)。

我正在运行 Mac OS X 10.8.4,并且安装了 Apple 的 JDK 1.6.0_51 以及 Oracle 的 JDK 1.7.0_25。我最近为一些需要它的预发布软件安装了 Oracle 的 1.8 预览版 JDK。现在,当我运行 /usr/libexec/java_home 时,我得到了这个:

$ /usr/libexec/java_home -V
Matching Java Virtual Machines (4):
    1.8.0, x86_64:  "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home
    1.7.0_25, x86_64:   "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home
    1.6.0_51-b11-457, x86_64:   "Java SE 6" /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
    1.6.0_51-b11-457, i386: "Java SE 6" /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

伟大的。

但是,运行:

$ java -version

回报:

java version "1.8.0-ea"

这意味着 Java 的默认版本当前是预发布版本,它破坏了一些“正常”包(在我的例子中是 VisualVM)。

我无法设置 JAVA_HOME,因为启动应用程序会忽略环境变量,即使从命令行启动(例如 $ open /Applications/VisualVM.app)也是如此。

那么,有没有我可以编辑的文件,我可以在其中全局设置我的 JVM 排序首选项?

(请不要告诉我启动 Java 首选项面板,因为这根本不起作用:它不包含任何有用的东西,只列出了我安装的 4 个 JVM 之一。)

更新:

Oracle JVM 位于 /Library/Java/JavaVirtualMachines 中。将 JDK 1.8 目录重命名为 jdk1.8.0.jvm.xyz 不会改变任何内容:java_home 仍然在正确的位置找到它,并且运行 /usr/bin/java 仍然执行 1.8 JVM。这不是synlinks等的问题。

类似问题的答案

虽然 this answer 提供了一种相当于 hack 的方法,可以将 Java 版本从 java_home 中移除,但它仍然没有回答 如何 java_home 选择其默认值以及用户是否可以{ 2}。

键入“which java”并按照面包屑导航。 /usr/bin/java 只是一个符号链接
去过也做过。 /usr/bin/java 指向 /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/javaVersions 目录不包含指向 1.8.0 JDK 的符号链接。相反,它包含一个名为 A 的目录,Current 指向该目录。 A 不是“JAVA_HOME。它有一个名为 Commands 的子目录,它确实有一个 java 命令,但它是一个不透明的通用二进制文件,谁知道什么。我怀疑它使用 java_home 等. 决定使用哪个 JVM。
如果这是题外话,请迁移而不是关闭。 FWIW,这是关于“程序员常用的软件工具”,所以关闭“离题”是不诚实的。
是的,这令人沮丧!我只想要一个 JDK,或者我可以轻松地在 1.7 和 1.8 之间切换的 2 个。
我发现这个 SO 答案对这个问题很有用:stackoverflow.com/a/44169445/2987755

I
Ian Roberts

我认为 JAVA_HOME 是你能做的最好的。 javajavac 等命令行工具将尊重该环境变量,您可以使用 /usr/libexec/java_home -v '1.7*' 为您提供合适的值以放入 JAVA_HOME 以使命令行工具使用 Java 7。

export JAVA_HOME="`/usr/libexec/java_home -v '1.7*'`"

但是标准的可双击应用程序包根本不使用安装在 /Library/Java 下的 JDK。使用 Apple 的 JavaApplicationStub 的旧式 .app 捆绑包将使用来自 /System/Library/Frameworks 的 Apple Java 6,而使用 AppBundler 构建但没有捆绑 JRE 的新式捆绑包将使用 /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home 中的“公共”JRE - 这很难-编码在存根代码中并且不能更改,并且您不能同时安装两个不同的公共 JRE。

编辑:我专门查看了 VisualVM,假设您使用的是 the download page 中的“应用程序包”版本,并且这个特定的应用程序不是 AppBundler 应用程序,而是它的主要可执行文件是一个调用数字的 shell 脚本其他 shell 脚本并读取各种配置文件。它默认从 /Library/Java 选择最新的 JDK,只要它是 7u10 或更高版本,或者如果您的 Java 7 安装是更新 9 或更早版本,则使用 Java 6。但是解开 shell 脚本中的逻辑,在我看来,您可以使用配置文件指定特定的 JDK。

创建一个包含该行的文本文件 ~/Library/Application Support/VisualVM/1.3.6/etc/visualvm.conf(将 1.3.6 替换为您正在使用的任何版本的 VisualVM)

visualvm_jdkhome="`/usr/libexec/java_home -v '1.7*'`"

这将迫使它选择 Java 7 而不是 8。


在我的系统上似乎不是这种情况。在安装 JDK 1.8 之前启动 VisualVM 是可行的。在 JDK1.8 之后,VisualVM 显示启动画面,然后死掉。将 JDK1.8 目录移出 /Library/Java 可恢复其运行能力。
@ChristopherSchultz 我查看了 VisualVM 包内部,结果发现它不是普通的 appbundler 应用程序。请参阅我的编辑以了解可能的解决方法。
对不起,我在您编辑之前写了我之前的评论。我将检查让 VisualVM 使用该技术运行,但它不太可能普遍适用。我有很多其他的基于 Java 的软件我运行得很好,比如 Eclipse、JasperReports iReport 等,它们都可能受此影响。我想我宁愿将 JDK1.8 目录移到其他地方,并在我实际需要它的(少数)次使用 JAVA_HOME 显式使用它。
是的,你是对的,JAVA_HOME 是要走的路,一般来说,你最好的选择是指定在其他情况下你需要的次要版本。根据反汇编,事实证明您可以 export JAVA_VERSION=1.7 使 java_home 默认显示 JKD7 而不是 JDK8,但这会破坏 java_home -v 1.6,因为 java-home 将其解释为附加约束并由于相互无法满足的约束而放弃,然后即使使用 --failfast 选项,也只使用默认的 1.8。
我不明白为什么系统偏好设置 Java 控制面板不只是提供一个可供选择的列表,而是不得不求助于 shell 脚本/命令。我怀疑这仅适用于在浏览器中运行的小程序...
v
void256

我也去过那里并到处搜索 /usr/libexec/java_home 的工作原理,但我找不到任何关于它如何确定它列出的可用 Java 虚拟机的信息。

我做了一些实验,我认为它只是执行 ls /Library/Java/JavaVirtualMachines,然后检查它在那里找到的所有运行时的 ./<version>/Contents/Info.plist

然后它通过 Info.plist 中包含的键 JVMVersion 对它们进行降序排序,默认情况下它使用第一个条目作为其默认 JVM。

我认为我们唯一可以做的就是更改 plist: sudo vi /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Info.plist,然后将 JVMVersion 从 1.8.0 修改为其他内容,使其排序到底部而不是顶部,例如 !1.8.0

就像是:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ...
    <dict>
            ...
            <key>JVMVersion</key>
            <string>!1.8.0</string>   <!-- changed from '1.8.0' to '!1.8.0' -->`

然后它神奇地从列表顶部消失:

/usr/libexec/java_home -verbose
Matching Java Virtual Machines (3):
    1.7.0_45, x86_64:   "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home
    1.7.0_09, x86_64:   "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_09.jdk/Contents/Home
    !1.8.0, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home

现在您需要注销/登录,然后:

java -version
java version "1.7.0_45"

:-)

当然,我不知道现在是否有其他问题,或者 java 的 1.8.0-ea 版本是否仍然可以正常工作。

您可能不应该这样做,而只需卸载 1.8.0。

但是到目前为止,这对我有用。


这对我有用。我不得不使用这个调整来让 Idea Sbt 插件在 MacOS 上为我工作。我在我的博客上提到它agilebuild.blogspot.com/2014/02/…
这可行,但似乎有点棘手,可能看起来不像标准操作程序。如果有更好的方法,我会徘徊。
我仍然想要一个解决方案,但是为了设置供 Intellij 使用的 JDK,我将它添加到我的 zshenv 中:export IDEA_JDK=/usr/libexec/java_home -v 1.7。我想我会为 JAVA_HOME 做同样的事情......
我设法使用这个答案来避免使用 Java 9 启动双击应用程序(由于 Keystore Store explorer 中的问题)。谢谢!
Installation of the JDK and the JRE on macOS 的摘录:在为 macOS 2012-006 安装 Java 后,/usr/bin/java 将找到已安装的 最新 JDK,并将其用于 { 3}。
U
User404

这实际上很容易。假设我们的 JavaVirtualMachines 文件夹中有这个:

jdk1.7.0_51.jdk

jdk1.8.0.jdk

假设 1.8 是我们的默认值,那么我们只需添加一个新文件夹(例如“旧”)并将默认 jdk 文件夹移动到该新文件夹。再做一次java -version,瞧,1.7!


难以置信,但它奏效了……感谢 Mac OS Mojave
D
Dan Walters

实际上,我在反汇编程序中看了一点,因为源不可用。

/usr/bin/java 和 /usr/libexec/java_home 都使用 JavaLaunching.framework。 JAVA_HOME 环境变量确实首先由 /usr/bin/java 和朋友(但不是 /usr/libexec/java_home)检查。框架使用 JAVA_VERSION 和 JAVA_ARCH 环境变量来过滤可用的 JVM。所以,默认情况下:

$ /usr/libexec/java_home -V
Matching Java Virtual Machines (2):
    11.0.5, x86_64: "Amazon Corretto 11"    /Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
    1.8.0_232, x86_64:  "Amazon Corretto 8" /Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home

但是设置,比如说, JAVA_VERSION 可以覆盖默认值:

$ JAVA_VERSION=1.8 /usr/libexec/java_home
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home

您还可以设置 JAVA_LAUNCHER_VERBOSE=1 以查看一些额外的调试日志,例如搜索路径、找到的 JVM 等,包括 /usr/bin/java 和 /usr/libexec/java_home。

过去,JavaLaunching.framework 实际上使用首选项系统(在 com.apple.java.JavaPreferences 域下)来设置首选 JVM 顺序,allowing the default JVM to be set with PlistBuddy - 但据我所知,该代码最近已被删除macOS 版本。环境变量似乎是唯一的方法(除了在 JDK 包本身中编辑 Info.plist。)

设置默认环境变量当然可以通过您的 .profile 或通过 launchd 完成,如果您需要在会话级别设置它们。


这是很好的信息,丹。使用 .profile 对我的用例(例如从启动板启动应用程序)没有用处,但 launchd 上的提示是一个很好的提示。我必须尝试一下,因为 Java 最近的版本控制疯狂意味着我同时安装了几代 Java,具有不同程度的(个人)信任。
这很棒!我正在运行一个稍微复杂的 Eclipse 设置并安装了几个 JDK。所以我只是为我需要的每个 Eclipse 配置创建了一个不同的 BASH 脚本,它只包含以下行:“JAVA_VERSION=1.8 /Applications/Eclipse.app/Contents/MacOS/eclipse &”
A
Andrei Rînea

我测试了“jenv”和其他设置“JAVA_HOME”但没有成功。现在我得到了以下解决方案:

function setJava {
    export JAVA_HOME="$(/usr/libexec/java_home -v $1)"
    launchctl setenv JAVA_HOME $JAVA_HOME
    sudo ln -nsf "$(dirname ${JAVA_HOME})/MacOS" /Library/Java/MacOS 
    java -version
}

(添加到 ~/.bashrc 或 ~/.bash.profile 或 ~/.zshrc)

像这样打电话:

setJava 1.8

java_home 将处理错误的输入。所以你不能做错事。 Maven 和其他东西现在会选择正确的版本。


j
jrypkahauer

这很简单,如果您不介意卷起袖子... /Library/Java/Home 是 JAVA_HOME 的默认值,它只是指向以下之一的链接:

/System/Library/Java/JavaVirtualMachines/1.?.?.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/jdk1.?.?_??.jdk/Contents/Home

所以我想更改我的默认 JVM/JDK 版本而不更改 JAVA_HOME 的内容... /Library/Java/Home 是当前 JVM/JDK 的标准位置,这就是我想要保留的...在我看来以最简单的方式以最少的副作用改变事物。

其实很简单。为了更改您使用 java -version 看到的 java 版本,您所要做的就是某个版本:

cd /Library/Java
sudo rm Home
sudo ln -s /Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home ./Home

我没有花时间,但是一个非常简单的 shell 脚本使用 /usr/libexec/java_home 和 ln 来重新指向上面的符号链接应该很容易创建......

一旦你改变了 /Library/Java/Home 指向的位置......你会得到正确的结果:

cerebro:~ magneto$ java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27) Java HotSpot(TM)
64-Bit Server VM (build 25.60-b23, mixed mode)

这不是这个东西的工作原理:/Library/Java/Home 确实是一个符号链接,但它指向 /System/Library/Frameworks/JavaVM.framework/Home,它本身就是一大堆符号链接,最终让你……一个神奇的命令,确定正确的 JRE发射。请注意,/usr/libexec/java_home 也链接到这个魔法。因此,您可以通过替换符号链接并指向单个 JRE 来中断一切,但您必须每次都更新它。显然没有像 set_preferred_jvm_version 或类似的命令。
但是,这种技术的优点是它不需要您在任何地方设置 JAVA_HOME。我将尝试使用这种技术,看看它是否会导致基于 Java 的程序使用“首选”Java VM 启动。我怀疑它会,但它非常脆弱。
好吧,这些天我在 .bash_profile 中有这个:export JAVA_HOME=`/usr/libexec/java_home -v 12`
这不适用于双击图标,这是重点。只能从命令行工作的解决方案是......不是解决方案。
d
duma

Oracle 的 uninstallation instructions for Java 7 为我工作。

摘抄:

卸载 JDK 要卸载 JDK,您必须具有管理员权限并以 root 身份或使用 sudo(8) 工具执行删除命令。导航到 /Library/Java/JavaVirtualMachines 并删除名称与以下格式匹配的目录:* /Library/Java/JavaVirtualMachines/jdk...jdk 例如,要卸载 7u6 : % rm -rf jdk1.7.0_06.jdk


这个问题不是关于卸载......而是关于从那些已安装的JVM中选择“主要”JVM......
M
Mo'in Creemers

有点晚了,但因为这是 Mac OSX 的一个持续问题......

我找到的最简单的解决方案是简单地删除 Apple 安装的 OpenJDK 内容。每次 Mac OSX 的更新到达时,它都会被安装,您需要再次将其删除。

如果您在 Mac 上使用 Java 为 Google App Engine 开发应用程序,这将非常有效。 OpenJDK 无法正常运行,Mac OSX Yosemite 升级附带的 Java 版本会导致 Eclipse Plug-in for App Engine 在每次部署时崩溃,并出现有用的错误:“读取超时”。


有趣...我认为 Apple 在这一点上已经完全删除了 Java。我不记得手动删除了 Apple 的 Java 1.6 JVM,它肯定不再存在了。无论如何,这并不能真正解决最初的问题,即在给定已安装的选择的情况下指定首选 JVM。
你是对的。它没有回答这个问题。它确实回答了这个问题:如果您删除正在使用的 JVM,则会使用列表中的“下一个”。也许这有帮助。
这是否解释了为什么在运行 jdk 8 安装后,它没有出现在 JavaVirtualMachines 文件夹中?无论我安装什么版本,我看到的都是“1.6.0.jdk”。
@whyoz 刚刚在 osx 10.10.2 上安装了 jdk-8u31-macosx-x64,并且虚拟机按预期安装在 JavaVirtualMachines 文件夹中。
您是否偶然运行 Parallels?我将它安装在 Parallels 的 Windows 端,并按预期安装了 8u31 ..只是没有在 Mac 端..
R
Rajitha Wijayaratne

可以很容易地添加到 java_home。

MacOS上JAVA_HOME的设置方式如下。例如,将以下内容添加到您的 ~/.zshrc 中。该脚本将选择您系统上安装的最新 JDK。

 JAVA_HOME=$(/usr/libexec/java_home)

当使用 -V 开关运行 java_home 脚本时,会列出当前安装的 JDK。我的 MacOS (Monterey) 默认 Java Home (JAVA_HOME) 就是这个。

/usr/libexec/java_home -V (Command to list installed JDK versions) 
        1.8.0_292 (x86_64) "AdoptOpenJDK" - "AdoptOpenJDK 8" /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

here 下载 Java OpenJDK 版本。确保下载 JDK .dmg 包。这有一个更新 JAVA_HOME 的安装程序。安装 v18.0 后,我的更改为以下。

/usr/libexec/java_home -V
Matching Java Virtual Machines (2):
    18 (x86_64) "Azul Systems, Inc." - "Zulu 18.28.13" /Library/Java/JavaVirtualMachines/zulu-18.jdk/Contents/Home
    1.8.0_292 (x86_64) "AdoptOpenJDK" - "AdoptOpenJDK 8" /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

现在它会选择最上面的项目,即版本 18。如果默认的最上面的项目不是优选的,则重新调整名称,以便您想要的名称是第一个列出的,如上面的 void256 所述。排序键在这里。

/Library/Java/JavaVirtualMachines/*/Contents/Info.plist.

现在所有工具都可以使用来自 JAVA_HOME 的 jdk。


三件事:(1) java_home 不影响 JAVA_HOME 环境变量。 (2) java_home 总是喜欢最新的版本。当我不想要最新的时,我在问如何设置默认版本。 (3) 这个问题是关于 not 从命令行运行的应用程序,因此环境变量和命令行行为不相关。
java_home 确实会影响 JAVA_HOME。将此添加到您的个人资料初始化中,例如。 ~/.zshrc -> 导出 JAVA_HOME=$(/usr/libexec/java_home)。这将自动拾取顶部项目。如果默认的顶部项目不是首选,则重新调整名称,以便您想要的名称是第一个列出的。排序键在这里 -> /Library/Java/JavaVirtualMachines/*/Contents/Info.plist。
C
Celandro

编辑:此信息专门针对 visualvm,不适用于任何其他 java 应用程序

正如其他人所说,您需要修改visualvm.conf

对于 Mac 上最新版本的 JvisualVM 1.3.6,安装目录已更改。

它当前位于 /Applications/VisualVM.app/Contents/Resources/visualvm/etc/visualvm.conf 中。

但是,这可能取决于您安装 VisualVM 的位置。找到 VisualVM 的最简单方法是在哪里启动它,然后使用以下命令查看该过程:

ps -ef | grep 视觉虚拟机

你会看到类似的东西:

... -Dnetbeans.dirs=/Applications/VisualVM.app/Contents/Resources/visualvm/visualvm...

您想要获取 netbeans.dir 属性并查找目录,您将找到 etc 文件夹。

在 visualvm.conf 中取消注释此行并更改 jdk 的路径

visualvm_jdkhome="/path/to/jdk"

此外,如果您的 visualvm 运行缓慢并且内存很大,我建议大大增加可用内存量并在服务器模式下运行它:

visualvm_default_options="-J-XX:MaxPermSize=96m -J-Xmx2048m -J-Xms2048m -J-server -J-XX:+UseCompressedOops -J-XX:+UseConcMarkSweepGC -J-XX:+UseParNewGC -J-XX:NewRatio=2 -J-Dnetbeans.accept_license_class=com.sun.tools.visualvm.modules.startup.AcceptLicense -J-Dsun.jvmstat.perdata.syncWaitMs=10000 -J-Dsun.java2d.noddraw=true -J-Dsun.java2d.d3d=false"

坏建议:修改特定应用程序的启动脚本可能会破坏应用程序,并且不能解决更改操作系统默认 JVM 的原始问题。
不幸的是,正如其他人所提到的,jvisualvm 不使用标准方法来选择 jvm。这是此应用程序的唯一解决方案。
正如我在 my answer 中所述,您无需修改应用程序包本身的任何内容,应用程序可以从 ~/Library/Application Support/VisualVM/1.3.6/etc/visualvm.conf 加载其配置。
T
Tony

我有类似的情况,以下过程对我有用:

在终端中,输入 vi ~/.profile 然后在文件中添加这一行,并保存 export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk.jdk/Contents/Home 其中版本是您计算机上的版本,例如as 1.7.0_25 退出编辑器,然后键入以下命令使其生效 source ~/.profile

然后输入 java -version 查看结果

    java -version 

什么是.profile?来自:http://computers.tutsplus.com/tutorials/speed-up-your-terminal-workflow-with-command-aliases-and-profile--mac-30515

.profile 文件是一个隐藏文件。它是一个可选文件,它告诉系统在其配置文件登录的用户登录时运行哪些命令。例如,如果我的用户名是 bruno,并且 /Users/bruno/ 中有一个 .profile 文件,则它的所有内容将在登录过程中执行。


从 Launchpad 启动 VisualVM 时,这将不起作用。从命令行启动从来都不是问题,因为您可以设置 JAVA_HOME 环境变量。
R
Rajat

MacOS 使用 /usr/libexec/java_home 来查找当前的 Java 版本。绕过的一种方法是更改 plist 文件,如上面@void256 所述。其他方法是备份 java_home 并用您自己的脚本 java_home 替换它,代码 echo $JAVA_HOME

现在,通过将以下命令添加到 ~/.bash_profile,将 JAVA_HOME 导出到所需的 SDK 版本。 export JAVA_HOME="/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home" launchctl setenv JAVA_HOME $JAVA_HOME /// 将环境变量设为全局

运行命令 source ~/.bash_profile 来运行上述命令。

任何时候需要更改 JAVA_HOME,他都可以在 ~/.bash_profile 文件中重置 JAVA_HOME 值。


任何依赖环境变量的东西都行不通。关键是通过 LaunchPad 等启动的应用程序不会具有该环境设置。上面的 plist hack 似乎是“最好的”,因为它实际上达到了预期的结果。我还不确定有什么缺点。请参阅具有相同问题的@Tony 的答案。
u
user2756423

我想将默认的 Java 版本从 1.6* 更改为 1.7*。我尝试了以下步骤,它对我有用:

从 /usr/bin 下删除了链接“java”

再次创建它,指向新位置:

ln -s /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/bin/java java

用“java -version”验证

Java 版本“1.7.0_51”Java(TM) SE 运行时环境(构建 1.7.0_51-b13)Java HotSpot(TM) 64 位服务器 VM(构建 24.51-b03,混合模式)


不回答问题:它不会影响 /usr/libexec/java_home 的行为。