34

为了加快 JVM 的启动时间,Sun 开发人员认为在安装 JVM 期间为平台预编译标准运行时类是一个好主意。这些预编译的类可以在例如以下位置找到:

$JAVA_HOME\jre\bin\client\classes.jsa

我的公司目前正在开发一个带有自己的 JRE 的 Java 独立应用程序,因此通过将我们自己的应用程序类也添加到此 jsa 文件中来加快我们的应用程序启动时间将是一个绝佳的选择。

我不相信 JSA 文件是由魔术创建的,所以:它是如何创建的?以及如何欺骗 JVM 合并我自己的类?

编辑:我已经发现了以下内容:

classes.jsa 由命令创建

java -Xshare:dump

可以在 中找到要合并到转储中的类列表$JAVA_HOME/jre/lib/classlist

我什至设法在这里添加我自己的类(并将它们添加到 rt.jar 中供 java 查找它们),并在类列表文件下生成我自己的校验和。

最后一个问题是:似乎只有包 java、com.sun 和 org.w3c 中的类被识别,如果我将相同的类留在原来的包中,它们将不会被加载。我在整个 OpenJDK 源代码中搜索了关于此的指针,但它似乎与保护域有关。如果有人对此主题足够感兴趣并且知识渊博,请添加一些指针供我进一步调查。

4

4 回答 4

11

你快到了,你只需要几个步骤就可以让它工作。要将您自己的类添加到 clients.js,您需要以下步骤:

  1. 你的类的限定名称(你有它)

  2. 这些类的类路径(你有)

  3. 知道如何重新计算校验和(你有)

  4. 转储新文件,提供您现在使用 Java 类进行预编译的类的类路径。

  5. 运行程序,提供用于转储新 classes.jsa 的相同类路径

要提供要添加到类列表中的类的类路径,请使用该-Xbootclasspath/a命令。当 JVM 搜索引导类所在的位置时,它将附加目录/JAR。classes.jsa 的默认空间很小,如果需要改进,可以使用-XX:SharedReadWriteSizeand-XX:SharedReadOnlySize命令。您的转储命令类似于以下内容:

java -Xshare:dump -Xbootclasspath/a:C:/myfiles/directoryA/;C:/myfiles/directoryB/;C:/myJars/myJar.jar;

最后一步就是正常运行java应用程序,记得开启共享模式。您还需要Xbootclasspath像在转储上添加一样添加 excatly。它看起来类似于:

java myapp.java -Xshare:on -Xbootclasspath/a:C:/myfiles/directoryA/;C:/myfiles/directoryB/;C:/myJars/myJar.jar;

现在,您放在类列表中的每个类都与在同一 JVM 中运行的其他实例共享。

于 2013-01-29T18:39:20.943 回答
11

从 Java 8u40(和嵌入式 Java 8u51)开始,Java 现在支持应用程序类数据共享 (AppCDS)(即共享存档中您自己的类)。在我们的嵌入式 Java 上,我们发现启动改进超过 40%!非常棒,因为我们几乎没有工作......

https://blogs.oracle.com/thejavatutorials/entry/jdk_8u40_released

于 2015-10-21T13:52:54.053 回答
8

有趣的想法。不过,当我读到它时,它用于跨 VM 共享数据和加速类加载,而不是编译。我不确定你会得到多少提升,但如果你在启动时已经有很大的延迟,那么它可能值得一试(尽管 VM 已经尝试减轻这种情况)。

至于你自己试试看,这个文件一般是在安装 Sun VM 时创建的,但你也可以控制它。一些细节在这个较早的 Sun Java 5类数据共享文档(您可能已经看过?)。一些 Sun Java 6 文档也多次提到它,但不要在文档中添加太多内容。似乎它最初是IBM VM 的一项功能。而且,为了继续链接转储,本文对此进行了一些解释。

我个人对它了解不多,所以我不知道你如何控制它。你可以重新生成它,但我不认为它是为了让你把自定义的东西放进去。此外,即使您可以“欺骗”它,也可能会违反某种 Sun/Oracle 许可证(例如,您不能弄乱 rt.jar 和重新分发)。而且,综上所述,我怀疑除非您的应用程序中有数千或数万个课程,否则您会看到启动时间的显着改善?

(我知道,这不是一个真正的答案,但它太大而无法放入评论中,我发现这个问题很有趣,所以我进行了一些调查,并将链接放在这里,以防有人发现相同的信息有用。)

于 2011-01-14T16:54:34.023 回答
0

花了一点时间弄清楚,但我有 4 个 Java8 VM(版本 1.8.0_162)使用共享类运行。以下脚本用于设置和测试共享,稍作修改即可在其他地方使用:

#!/bin/bash

# Libraries to load
LIBS1="./lib/protobuf-java-2.6.1.jar:\
./lib/jetty-server-9.2.18.v20160721.jar:./lib/jetty-util-9.2.18.v20160721.jar:./lib/servlet-api-3.1.jar:./lib/jetty-http-9.2.18.v20160721.jar:./lib/jetty-io-9.2.18.v20160721.jar:\
./lib/derby.jar:\
./lib/json-simple-1.1.1.jar:"
LIBS2=":./lib/GTFS.jar"

# Uncomment these lines for the first phase where you are determining the classes to archive. During this phase aim to get as many classes loaded as possible
# which means loading a schedule and retrieving the stop list and next vehicle information
#
#APPCDS="-Xshare:off -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -XX:DumpLoadedClassList=../GtfsAppCds.lst"
#java -Xmx512m $APPCDS -Dderby.system.home=database -classpath $LIBS1$LIBS2 com.transitrtd.GtfsOperatorManager

# Uncomment these lines when the class list is created and run to create the shared archive. Classes marked as unverifiable will need to be removed from the
# archived class list in GtfsAppCds.lst and the lines below run again. LIBS2 above contains jars which are left out of the archive. These are jars which change
# frequently and would therefore cause the archive to be frequently rebuilt.
#                                                                                                                                                                                                               
#APPCDS="-Xshare:dump -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -XX:SharedClassListFile=../GtfsAppCds.lst -XX:SharedArchiveFile=../GtfsAppCds.jsa"
#java -Xmx512m $APPCDS -classpath $LIBS1

# Uncomment these lines when wishing to verify the application is using the shared archive.
#
#APPCDS="-Xshare:on -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -XX:SharedArchiveFile=../GtfsAppCds.jsa -verbose:class"
#java -Xmx512m $APPCDS -Dderby.system.home=database -classpath $LIBS1$LIBS2 com.transitrtd.GtfsOperatorManager

请注意,共享存档文件(即 jsa 文件)取决于体系结构,需要在每个目标平台类型上构建。

此外,如果 jar 使用密封包,则会引发安全异常,请参阅

https://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html

有关密封包装的信息。上面的derby.jar就是这种情况,但可以通过解压 jar 文件、将清单中的Sealed:true替换为Sealed:false并重新打包来解决问题。

用旧版本的 java 构建的 jar 不能在共享存档中使用,在上述情况下,需要将 derby 版本从 10.10 升级到 10.14 才能受益。

于 2018-04-18T15:09:17.847 回答