JDK 9 中一些需要提防的坑

songqingtian 7年前
   <p style="text-align: center;"><img src="https://simg.open-open.com/show/b5cd99196d938598f06cd247d2b36a21.png"></p>    <p>JDK 9正处于 <a href="/misc/goto?guid=4958877223895328783" rel="nofollow,noindex">开发的最后阶段</a> , 向着9月21号的发布目标冲刺。 <a href="/misc/goto?guid=4958858572094367507" rel="nofollow,noindex">Java 平台模块系统</a> 的公开评审投票基本上被 <a href="/misc/goto?guid=4959754508251671525" rel="nofollow,noindex">一致通过</a> ,所以目前一切都可以回归正常了。</p>    <p>你可在此处下载 <a href="/misc/goto?guid=4959754508333790979" rel="nofollow,noindex">OpenJDK 9</a> (尝鲜版)。</p>    <p>最近我在写一篇文章,题目是“ <a href="/misc/goto?guid=4959754508416342273" rel="nofollow,noindex">JDK 9</a> 中的 55 个新特性”。在其中,我试图把重点放在所有非 JPMS 内容上。这也表明 JDK 9 中有几个改动的部分,可以让人们了解到其与早期版本的兼容性。我注意到也有一些与之相关的问题出现在了  <a href="/misc/goto?guid=4959754508490722197" rel="nofollow,noindex">Stackoverflow</a> 上。</p>    <p>这篇博客是我能够找到的你在将应用程序迁移到 JDK 9 时所有可能需要进行改动的内容的总结。我不会在此处讨论 JPMS 、非公共的封装类、对反射访问的影响等。本文是一系列不同问题的集合。这个集合只涉及一些你需要注意的其他事情。</p>    <p>3. JDK 版本字符串(JEP 223):老的定义 JDK 版本的方法相当混乱。例如,我们有 JDK 8u131 ,但是如果你运行 java -version ,你会得到 java version "1.8.0_131" 。为了从人类和应用程序角度简化这个(定义版本的方法),现在的版本格式是 JDK $MAJOR.$MINOR.$SECURITY.$PATCH ,所以在 JDK9 上的 java -version 将返回 java version "9"(一旦发布最终的 release 版,我们获取更新之后该版本号就会改动)。这里重要的是,如果你在代码中使用 JVM 的版本字符串,并依赖于当前版本格式,那么在 JDK 9 中你必须进行代码改动才能正确运行。</p>    <p>4. Thread.stop(Throwable) 现在会抛出一个 UnsupportedOperationException ,它之前并没有抛出类似异常。由于其自身缺乏线程安全性,因此不推荐使用此方法。另一个不带参数的 Thread.stop() 版本仍然可以使用,并且不会抛出异常(但仍然不推荐使用,并强烈建议不要使用此函数)</p>    <p>5. Java 网络登录协议(Java Network Launch Protocol ,JNLP)已更新,以支持严格的配置文件解析。现在使用的格式符合 XML 规范,要求“&”版本范围连接器表示为“&amp;”。配置解析目前是严格的,这意味着一些在旧版本的 Java 中可以使用的文件现在将会产生错误。 有关更多详细信息,请参见 <a href="/misc/goto?guid=4959754508574693617" rel="nofollow,noindex">JSR 52维护页面</a> 。</p>    <p>6. 与 JPMS 相关的扩展机制(可选软件包)和已批准的标准覆盖机制都已被删除,并使用 JPMS 对应物替代。因此,$JAVA_HOME/lib/ext 和 $JAVA_HOME/lib/endorsed 的目录已被删除。如果你重新创建这些目录,并尝试把东西放在这些目录下,祈祷他们能工作,这是不可能的。JVM 在查找到这些目录时将无法启动,你将收到以下错误消息:</p>    <p>/lib/ext exists, extensions mechanism no longer supported; Use -classpath instead.</p>    <p>Error: Could not create the Java Virtual Machine.</p>    <p>Error: A fatal exception has occurred. Program will exit.</p>    <p>7. 六个之前已弃用的公共方法已经被删除。这是一件相当大的事情,因为这些是 Java 历史上第一次要删除的API。已删除的方法包括java.util.jar.Pack200,java.util.jar.Unpack200中的addPropertyChangeListener()、removePropertyChangeListener(),以及 java.util.logging.LogManager类。</p>    <p>8.作为 <a href="/misc/goto?guid=4959754508646869989" rel="nofollow,noindex">Java Authentication and Authorization Service (JAAS,Java授权认证服务)</a> 的一部分的 <a href="/misc/goto?guid=4959754508735758675" rel="nofollow,noindex">com.sun.security.auth.callback.DialogCallbackHandler</a> 类已被删除。它在 JDK 8 中就已被弃用。</p>    <p>9. JRE 版本选择将不再可用。过去有两种做法可以实现 JRE 版本选择。第一个是在命令行中使用 -version: 选项。如果使用该选项,JVM 将中止而不再启动。第二种方式是从 jar 文件的 manifest 。在这种情况下,JDK 9 将忽略该指令,但会正常启动。有人觉得,与改变命令行相比,强迫人们改变 manifest 太麻烦了。请注意,-version 选项(不带后面的冒号和版本号)仍然可以报告你所使用的 Java 运行时版本。</p>    <p>10. 废弃的GC选项已被移除( <a href="/misc/goto?guid=4958856739104794457" rel="nofollow,noindex">JEP 214</a> )。 在 JDK 8( <a href="/misc/goto?guid=4959754508845459583" rel="nofollow,noindex">JEP 173</a> )中已经弃用了一些详细的 GC 选项和选项组合。这些将不会被识别,并将导致 JVM 在启动时中止。要注意的选项如下所示</p>    <p>-XX:-UseParNewGC -XX:+UseConcMarkSweepGC</p>    <p>-XX:+UseParNewGC</p>    <p>-Xincgc</p>    <p>-XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC</p>    <p>-XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC -XX:-UseParNewGC</p>    <p>-XX:+UseCMSCompactAtFullCollection</p>    <p>-XX:+CMSFullGCsBeforeCompaction</p>    <p>-XX:+UseCMSCollectionPassing</p>    <p>在 JDK 9 中,concurrent-mark-sweep (iCMS) 的增量模式已被移除,目前的计划是在 JDK 10 中完全删除 CMS 。</p>    <h3>命令行选项</h3>    <p>这对我来说似乎是一个很大的变化,但到目前为止,我还没有看到它被突出强调过(或有良好的记录文档)。</p>    <p>除了上述 GC 选项之外,在 JVM 如何处理日志记录中有重大改动。 <a href="/misc/goto?guid=4958856738920306786" rel="nofollow,noindex">JEP 158</a> 引入了统一日志记录系统,并且该系统被用在 GC 日志中,用于提供统一的 GC 日志记录( <a href="/misc/goto?guid=4959725654861659911" rel="nofollow,noindex">JEP 271</a> )。这会影响许多常用的 GC 日志记录命令行选项以及其他一些操作。</p>    <p>为了弄清楚发生了什么改动,我从 OpenJDK 源代码(特别是 src/share/vm/runtime/globals.hpp 文件)中提取了相关的行。通过做 diff ,我能够得到所有从 JDK 8 中删除的 -XX 选项以及已添加到 JDK 9 中的所有 -XX 选项的列表。然后,我写了一个脚本,使用一个简单的应用程序依次查看使用在 JDK 8 中支持但在 JDK 9 中已删除的选项的结果。</p>    <p>对 -XX 选项的更改可以分为三组:</p>    <p>已忽略的命令行选项</p>    <p>如果使用其中的一个,您将收到以下警告消息,但 JVM 将正常启动。</p>    <p>Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option <Option>; support was removed in 9.0</p>    <ul>     <li> <p>AdaptiveSizePausePolicy (自适应大小暂停策略)</p> </li>     <li> <p>CodeCacheMinimumFreeSpace(代码缓存最小空闲空间)</p> </li>     <li> <p>DefaultThreadPriority(默认线程优先级)</p> </li>     <li> <p>JNIDetachReleasesMonitors(JNI分离释放监视器)</p> </li>     <li> <p>LazyBootClassLoader(惰性类启动器)</p> </li>     <li> <p>NmethodSweepCheckInterval(N方法扫描检查间隔)</p> </li>     <li> <p>NmethodSweepFraction(N方法扫描片段)</p> </li>     <li> <p>PrintOopAddress(打印OOP地址)</p> </li>     <li> <p>ReflectionWrapResolutionErrors(反射包装处理错误)</p> </li>     <li> <p>StarvationMonitorInterval(饥饿监视间隔)</p> </li>     <li> <p>ThreadSafetyMargin(线程安全边界)</p> </li>     <li> <p>UseAltSigs(使用alt信号)</p> </li>     <li> <p>UseBoundThreads(使用绑定线程)</p> </li>     <li> <p>UseCompilerSafepoints(使用编译器安全点)</p> </li>     <li> <p>UseFastAccessorMethods(使用快速访问方法)</p> </li>     <li> <p>UseFastEmptyMethods(使用快速空方法)</p> </li>     <li> <p>BackEdgeThreshold(后边缘阈值)</p> </li>     <li> <p>PreInflateSpin(预浸旋转)</p> </li>    </ul>    <p>已弃用的命令行选项</p>    <p>这些选项将在 JVM 启动时触发警告,或者告诉你 JVM 将使用哪个选项,或者告诉你应该使用哪个选项。其中大部分与统一的 GC 日志有关。</p>    <p>以下是两个关于警告信息的示例:</p>    <p>warning][gc] -XX:+PrintGC is deprecated. Will use -Xlog:gc instead.</p>    <p>Java HotSpot(TM) 64-Bit Server VM warning: Option CreateMinidumpOnCrash was deprecated in version 9.0 and will likely be removed in a future release. Use option CreateCoredumpOnCrash instead.</p>    <p>下表给出了 JDK 8 中的命令行选项及其在 JDK 9 中对应的替换选项。</p>    <table>     <tbody>      <tr>       <td><strong>JDK 8 Option</strong></td>       <td><strong>JDK 9 Replacement</strong></td>      </tr>      <tr>       <td>PrintGC</td>       <td>-Xlog:gc</td>      </tr>      <tr>       <td>PrintGCDetails</td>       <td>-Xlog:gc*</td>      </tr>      <tr>       <td>CreateMinidumpOnCrash</td>       <td>CreateCoredumpOnCrash (suggestion)</td>      </tr>      <tr>       <td>DefaultMaxRAMFraction</td>       <td>MaxRAMFraction (suggestion)</td>      </tr>      <tr>       <td>TraceBiasedLocking</td>       <td>-Xlog:biasedlocking=info</td>      </tr>      <tr>       <td>TraceClassLoadingPreorder</td>       <td>-Xlog:class+preorder=debug</td>      </tr>      <tr>       <td>TraceClassResolution</td>       <td>-Xlog:class+resolve=debug</td>      </tr>      <tr>       <td>TraceMonitorInflation</td>       <td>-Xlog:monitorinflation=debug</td>      </tr>      <tr>       <td>TraceRedfineClasses</td>       <td>-Xlog:redefine+class*=info</td>      </tr>      <tr>       <td>TraceSafepointCleanupTime</td>       <td>-Xlog:safepoint+cleanup=info</td>      </tr>      <tr>       <td>TraceClassLoading</td>       <td>-Xlog:class+load=info</td>      </tr>      <tr>       <td>TraceLoaderConstraints</td>       <td>-Xlog:class+loader+constraints=info</td>      </tr>      <tr>       <td>ConvertSleepToYield</td>       <td>NONE</td>      </tr>     </tbody>    </table>    <p> </p>    <p>来自:https://www.oschina.net/translate/jdk-9-pitfalls</p>    <p> </p>