我正在尝试将我们的一个系统从 java 8 迁移到 java 9,在 java 8 中运行正常的大约三分之一的单元测试失败,并出现以下错误:
java.io.IOException: Can not attach to current VM
Google 带我看了几页,我很快就明白了,在 java 9 中,默认行为已更改,以防止附加到当前 VM,并返回到旧的方式,您需要将系统属性
jdk.attach.allowAttachSelf
设置为 true。
在 IntelliJ 中设置此项时,测试工作正常。更改 build.gradle 以包含此内容时,效果相同:
test {
jvmArgs '-Djdk.attach.allowAttachSelf=true'
}
但是,我宁愿在全局范围内进行此设置,这样我就不需要破解我的 build.gradle 和 IntelliJ。
我在 ubuntu 上运行 java 9,我更改了
/etc/profile.d/jdk.sh
以包含此内容:
export JDK_JAVA_OPTIONS="-Djdk.attach.allowAttachSelf=true"
运行 Gradle 构建时,我可以看到设置被选取,因为我在构建输出中看到了以下内容:
NOTE: Picked up JDK_JAVA_OPTIONS: -Djdk.attach.allowAttachSelf=true
但是,测试不断失败并出现相同的 IOException。
那么我做错了什么,我应该如何解决它?
提前感谢您的投入。
我的测试是使用 Surefire 插件运行的, 如果在 argline 中添加了所述 vm 参数,则测试开始工作。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14.1</version>
<configuration>
<argLine>-Djdk.attach.allowAttachSelf=true </argLine>
</configuration>
</plugin>
我在构建 gradle 项目时也遇到了同样的问题。很多虚拟机绑定问题。添加
JDK_JAVA_OPTIONS=-Djdk.attach.allowAttachSelf=true
在“修改配置”窗格中的环境变量确实解决了这个问题。但是,向“VM 选项”添加任何内容都没有任何作用。
我认为你可以使用 Unsafe。
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
Field ALLOW_ATTACH_SELF = Class.forName("sun.tools.attach.HotSpotVirtualMachine").getDeclaredField("ALLOW_ATTACH_SELF");
Object allowAttachSelfBase = unsafe.staticFieldBase(ALLOW_ATTACH_SELF);
long allowAttachSelfOffset = unsafe.staticFieldOffset(ALLOW_ATTACH_SELF);
boolean defaultValue = unsafe.getBooleanVolatile(allowAttachSelfBase, allowAttachSelfOffset);
unsafe.putBooleanVolatile(allowAttachSelfBase, allowAttachSelfOffset, true);
// Do your agent
unsafe.putBooleanVolatile(allowAttachSelfBase, allowAttachSelfOffset, defaultValue);
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) {
throw new RuntimeException(e);
}