【问题标题】:Performance hit using JAR files使用 JAR 文件的性能下降
【发布时间】:2011-05-09 14:47:17
【问题描述】:

在将类打包到 Jar 文件中而不是仅仅运行未打包的类时,您是否会受到性能影响?假设您有一个大型应用程序,如果需要从存档中提取许多文件,这会减慢您的应用程序吗?

【问题讨论】:

    标签: java class jar


    【解决方案1】:

    不,不会。这些类被加载到内存中并从那里使用。

    它可能会稍微减慢启动时间,但这可以忽略不计。此外,如果您在运行时积极加载和卸载类,可能会有差异,但仍然可以忽略不计。

    底线是:出于性能原因,您不应打开 jar 包。

    【讨论】:

    • 只在需要时才加载类是不是不正确?确定不是启动时一次性加载?
    • 您有什么建议可以加快启动速度吗?我们的jar文件很大,启动需要很长时间;大约 10 分钟;这正在减慢我们的开发进程。当我们使用 IntelliJ IDE 启动时,相同的项目大约需要 2 到 3 分钟,因为它不直接使用 jar 文件
    【解决方案2】:

    从展开的目录加载类不太可能带来任何性能优势。如果是这样的话,那么一些 Java 应用程序(尤其是 Java EE 应用程序服务器)在运行爆炸的 JAR 时会看到性能优势。

    没有性能优势的一个更科学的原因是 JAR 通常是压缩的,并且可以从磁盘上一组非常特定的扇区访问,这在爆炸 JAR 的情况下不太可能。这也意味着在使用爆炸 JAR 中的类时,性能很可能会受到影响。

    此外,类加载操作通常只执行一次。除非永久代经历了多个类加载和卸载周期(对于规模较小的永久代),否则类加载不太可能是导致性能不佳的一个因素。

    【讨论】:

      【解决方案3】:

      根据压缩情况,启动时间可能会稍长一些,但一旦完全运行,应该不会影响性能

      【讨论】:

        【解决方案4】:

        取决于读取压缩数据+解压缩的时间是否比读取未压缩数据的时间长,然后只在启动时。

        【讨论】:

          【解决方案5】:

          不,不会。在大型应用程序中,效果可能是负面的。典型的 I/O 开销高于未解压缩的增益。此外,罐子有一个索引,可以提高重复访问的速度。遍历文件系统中的目录树的开销通常比访问索引的jar要高。

          一旦您的操作系统开始在内存中缓存文件,性能问题就会消失。从 Java 6 开始,JRE 将首先在 Windows 上检查缓存。如果缓存是热的,需要几分钟才能加载的应用程序将在 10-20 秒内加载。目录中的 jar 和 *.class-files 的效果应该类似。请记住不要将此效果与您正在进行的优化混淆,并始终在冷启动时进行测量。

          【讨论】:

            【解决方案6】:

            这里有一个折衷,但大多数情况下,您希望使用 JAR 文件。

            如果你只加载一个类,你可以将它作为一个文件加载,而不是从 JAR 文件中读取它。但是,您可能会花费更多时间来查找该类,尤其是当它具有多个目录且位于众多其他类中时。

            如果您要加载许多类,将它们暴露出来将是一个很大的损失:将需要分别打开、读取和关闭每个文件的步骤,而从 JAR 文件中读取只需执行一次。 (假设您在类加载之间保持 JAR 打开;如果您正在执行多个类加载,则为每个类加载重新打开 JAR 将是一个大问题。)

            更详细地说,对于类加载,这里有两种策略:

            (1) 暴露在磁盘上的类。 (2) 打包在 JAR 文件中的类。

            对于 (1),将根目录向下移动到目标类会有一些成本。这可能是按需增量完成的,也可能最初是为整个目录树完成的。如果需要列出非常多的目录,那成本会相当大。

            对于 (1),还有打开和阅读各个课程的成本。对于一个类,这比打开 JAR 的成本要低,但对于许多类,由于打开单个文件的额外开销,成本最终会变得更大。

            对于 (2),初始 JAR 打开需要额外的成本,它将读取 JAR 的条目索引。这将与 JAR 中的条目数成正比。

            对于(2),在读取单个资源进行类加载时,会存在寻找、解压和验证类资源的成本。解压缩通常是一种清洗,因为压缩减少了读取时间,但增加了解压缩步骤。验证是额外的,但可以关闭。

            除此之外,对于 (1),如果读取整个目录,这将比 (2) 中打开 JAR 的成本大得多。在 (1) 中,如果您以某种方式增量读取目录,最初可能会更快,但读取单个类的成本最终会大于 (2) 的 JAR 读取成本。 “最终”可能不会有太多的类加载。

            为了比较这两种情况,还需要考虑以下其他问题:

            (1) 在原始存储和文件系统开销方面,将文件保存在磁盘上的开销远高于仅保存一个 JAR 文件的开销。

            (2) 将类作为单个文件访问会占用多个文件句柄;从 JAR 访问类将只使用一个。

            (3) 传输类变得很麻烦,因为您必须复制目录,或者打包、复制和解包。复制多个单独的文件比复制单个 JAR 文件要昂贵得多。

            (4) 使用 JAR 可让您使用内置于类加载 APIS 中的 JAR 签名功能。

            在应用程序服务器的空间中,在查看类如何在 WAR 文件下打包时,选择 (1) 和 (2) 的影响就显现出来了。即类可以打包在WEB-INF/classes 下,也可以打包在WEB-INF/lib 下的JAR 文件中。如果应用服务器解压 WAR 文件以便从运行的服务器访问,那么在 WEB-INF/classes 下拥有类会增加非常大的开销。应用服务器通常更喜欢将类保存在 JAR 文件中。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2023-03-06
              • 2015-03-20
              • 1970-01-01
              • 2020-02-05
              • 2011-11-07
              • 2014-03-02
              • 2014-05-19
              相关资源
              最近更新 更多