Java Web Start 导致执行缓慢

3
我有一个应用程序,我正在使用Java Web Start部署它。在进行单元测试时,我注意到了一个小问题:每当我的应用程序使用Java Web Start运行时,特定的操作需要很长时间才能执行。然而,在本地运行时,它非常快。
我所说的特定操作是读取一个大型(5k行)Excel文件以解析它。这是代码行:
Workbook wb = WorkbookFactory.create(new FileInputStream(new File(inputFile.getText())));

为了找出问题,我添加了一种记录时间的方法:
long time1 = System.currentTimeMillis();
Workbook wb = WorkbookFactory.create(new FileInputStream(new File(inputFile.getText())));
long time2 = System.currentTimeMillis();
long diff = time2 - time1;
double seconds = (double)diff / (double)1000;
DecimalFormat df = new DecimalFormat("#,##0.00");
System.out.println("Elapsed Time: " + df.format(seconds) + " seconds.");

以下是输出结果:

(本地)

Elapsed Time: 4.83 seconds.

(JWS) Java网络启动
Elapsed Time: 35.52 seconds.

但是,随后立即运行(在Java Web Start上)会出现以下情况:
Elapsed Time: 1.61 seconds.

我的猜测是这与POI库有关(特别是读取POI所需的库文件大小,更具体地说是13 MB的ooxml-schemas-1.0.jar库文件)。那么,我的问题是:假设是库文件大小的原因,有没有什么方法可以防止这种情况发生?我已经通过控制面板打开了库缓存,为什么似乎仍需要缓存库文件?一旦它被加载,就很快。但第一次加载需要很长时间。
以下是控制面板的图像,显示我允许它存储库:enter image description here 有人见过这种行为吗?没有SSCCE,因为……好吧,如何在Java Web Start问题中发布SSCCE呢?

参见:https://dev59.com/oX_aa4cB1Zd3GeqPzSQe - Kolban
4个回答

1
我可以看出有两件事情是无法帮助的。不确定它们是否会完全解决差异,但至少有些...
首先,这行代码
WorkbookFactory.create(new FileInputStream(new File(inputFile.getText())));

你原本拥有一个完好的文件对象,现在你正在浪费大量时间和资源将其全部缓存到内存中。正如 POI文档中明确解释的那样, 如果你有一个文件,请直接使用它!你可以节省时间和内存,将其(如文档所示)更改为:
WorkbookFactory.create(new File(inputFile.getText()));

.

其次,从POI组件页面开始: poi-ooxml需要poi-ooxml-schemas。这是ooxml-schemas jar的大幅缩小版本...通常仅在开发时需要较大的ooxml-schemas jar。
因此,除非您有一些特殊需求,否则请将完整的ooxml-schemas jar替换为更小的poi-ooxml-schemas jar,它将涵盖所有常见用例。这也会使您的加载速度更快。

正确,但没有解释WebStart与本地时间差异。 - finnw
我花了很多时间为这个应用程序配置POI库。不要问我为什么,但是poi-ooxml-schemas jar文件没有起作用。整个过程相当混乱,花费了我很长时间才弄清楚,但现在它可以工作了。但是,是的,这个小库没有起作用。 - ryvantage
此外,WorkbookFactory.create(new File(inputFile.getText())); 抛出编译器错误,没有 WorkbookFactory.create(File file) 方法。不确定为什么他们会在文档中包含它?这就是我使用 FileInputStream 的唯一原因。 - ryvantage
1
听起来你正在使用一个古老版本的POI。升级到最新版本,很可能两者都能正常工作! - Gagravarr
嗯...确实是POI 3.5,但那是因为我无法让3.9正常工作。圆钉穿过了方孔,哈哈 :) - ryvantage
尝试使用3.10 beta 2版本,这是目前最新的版本。自3.5版本以来修复的错误列表相当长,因此升级后您将获得许多修复!请参考http://poi.apache.org/changes.html#3.5-final。 - Gagravarr

1
如果你在jnlp文件中错误地将download属性设置为lazy,那么你应该声明你想要急切地下载这个库。
<resources>
        <jar download="eager" href="uploads/lib/guice-multibindings-3.0.jar"/>
</resources>

这意味着应用程序启动之前,它们将被缓存。
默认情况下,jar和nativelib资源将被急切地下载,即它们在应用程序启动之前被下载并在本地可用于运行应用程序的JVM。 jar和nativelib元素还允许将资源指定为lazy。这意味着在应用程序启动之前不必将资源下载到客户端系统。
来自http://docs.oracle.com/javase/7/docs/technotes/guides/javaws/developersguide/syntax.html

download 偏好设置没有在 .jnlp 文件中指定,因此 eager 是默认设置。无论哪种方式,我都不认为它每次都会下载库文件。我认为问题是它需要花费很长时间来加载库,而非下载它们。 - ryvantage
是的,这是jar资源的默认值。但是,如果例如它是另一个jnlp中的嵌套依赖项,那么它可能有帮助。 - Aksel Willgert
没有其他的.jnlp文件。只有一个简单的Netbeans生成的launch.jnlp。自从j7u25以来,我已经放弃了Component.jnlp - ryvantage
也许可以检查一下:https://dev59.com/klbTa4cB1Zd3GeqP_YWM - Aksel Willgert
哇,绝对是一个有趣的线程 :) 但是我的 .jars 已经正确地索引了。看起来 Netbeans 修复了那个 bug。 - ryvantage

1
我遇到了类似的问题,但是是在加载.docx文档(XWPFDocument)时出现的。在本地操作时,加载文件只需要不到1秒钟;然而,通过Java Web Start进行操作时,我的加载时间需要约35秒,甚至我的同事需要半小时。以下是我解决问题的方法,希望能够解决这个问题。
罪魁祸首是Apache XMLBeans库,或者更准确地说是它在Apache POI中被使用的方式有误。Apache POI发布版附带的XMLBeans库版本为2.3.0,jar文件名为xmlbeans-2.3.0.jar。如果你在本地启动程序时将其包含在类路径中,它将正常工作。但是,如果你将其作为资源包含在.jnlp文件中并使用Web Start启动程序,它将像你所描述的那样工作得非常缓慢。如果你打开Java控制台并将跟踪级别设置为5,你会发现当你加载.docx文件时,程序会寻找一个名为xbean.jar的资源,即使你的.jnlp文件中可能根本没有这个资源。这将导致程序一直寻找资源直到超时,并且可能会尝试多次,从而导致加载时间变慢。

关于这个问题,2011年POI Bugzilla(Bug 51660)中有一个错误报告。

我通过下载XMLBeans 2.5.0版本解决了这个问题,不再包括xmlbeans-2.3.0.jar,而是在类路径和.jnlp文件中作为资源包括xbean.jarjsr173_1.0_api.jar


很棒的答案。我稍后会研究一下并看看它是否有效。仍然没有解决这个问题。我会告诉你的。 - ryvantage
@Mxalis 这看起来像一个很好的答案,但我有困难理解最后一句话。我找不到可下载的XMLBeans v2.5.0。你(或其他任何人)有这样的链接吗? - Kolban
看起来您不能从XMLBeans项目页面下载它了,但它仍然托管在Apache档案库中,位于http://archive.apache.org/dist/xmlbeans/binaries/(文件为xmlbeans-2.5.0.zip)。您需要包含的文件是lib / xbean.jar和lib / jsr173_1.0_api.jar,而不是xmlbeans-2.3.0.jar。 - Mxalis

1

针对任何分析结果,您应该仔细检查<j2se/>元素中指定的<resources/>属性,并将它们与开发环境中的进行比较。特别是要查看那些影响性能的属性,例如堆大小和虚拟机类型:

<resources>
    <j2se
        version="1.6+"
        initial-heap-size="128m"
        max-heap-size="256m"
        java-vm-args="-server"/></resources>

我的所有j2se标签上只有<j2se version="1.7+"/>。我认为我不需要手动调整堆大小。这是一个非常(非常)小且轻量级的应用程序。它只有一个框架。 - ryvantage
当您比较这两个环境的设置时,是否存在任何差异? - trashgod
不,我没有向命令行添加任何参数或指定特定内容。在进行单元测试时,我通过Netbeans进行开发和运行,因此除非我不知道Netbeans的“运行”与命令行的“java myjar.jar”不同.... - ryvantage
使用 javaws 启动针对您的 JAR 的 .jnlp;附加 NetBeans 分析器以查看发生了什么。 - trashgod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接