【问题标题】:JVM memory usage, one JVM with threads or four JVM for each of my four apps?JVM 内存使用情况,一个带线程的 JVM 还是我的四个应用程序中的每个应用四个 JVM?
【发布时间】:2012-06-12 19:06:50
【问题描述】:

我目前有四个不同的 java 应用程序,它们由 .bat 文件启动的 jar 运行,这些文件位于 Windows XP Embedded 开始菜单的启动文件夹中。我也启动了 Firefox。现在,Firefox 或其中一个 Java 应用程序刚刚关闭。猜我内存不足(Win XP Embedded with 512 MB RAM)。

四个 Java 应用程序是,

  • HMI 后端(使用 Spark“微”框架构建)
  • 一种记录器应用程序,可将来自 PLC 的数据记录到 H2 数据库中。这通过使用 Timer/Timertask
  • h2 数据库服务器
  • 执行定期作业的调度程序。这通过使用 Quartz。

因此,这些 Java 应用程序中的每一个都在它们自己的 JVM 中启动(据我所知)。第一个问题是:我能否通过在一个 JVM 而不是四个 JVM 中运行这四个应用程序来降低它们的内存使用量。如果是这样,我应该使用线程来启动这些应用程序吗?

除此之外,我应该做的第一件基本事情是降低内存占用,这对于我这样的“真正的”Java 编程来说是相当新的。 H2连接池,重用对象还有什么? Jconsole 和 Xmx 的东西?

可能很天真,但我真的认为,嘿,GC 会为我处理“一切”。可能不会? =)

编辑: HMI 后端使用 Jetty 网络服务器。此外,所有代码要么是开源的,要么是由我构建的。

编辑 2: Web 框架:http://www.sparkjava.com/。我通过框架而不是通过 Jetty (jetty-webapp-7.3) 提供静态媒体。这可能是为了提高内存使用率而需要考虑的事情? HMI Web 应用程序的其他组件是 freemarker 模板引擎、gson、servlet-api-3、slf4j 和 log4j。

也许在启动 webapp 时尝试在线程中启动记录器和调度程序是可能的。然后只运行两个 JVM。一个用于 webapp,一个用于数据库服务器。

我使用的是 Java 7,它是一个 32 位系统。它有望用于生产用途(或者我遇到了麻烦)。

【问题讨论】:

  • 我感觉所有作业都紧密集成,因此您应该尝试使用一个主来运行它们。这将减少内存需求和 CPU 需求。
  • @tom -- 我不熟悉提到的一些组件,但在我看来它们本质上是“黑匣子”,不能随意重新架构?还是我误会了?
  • 这是我们说的虚拟机吗?因为现在 512 MB RAM 似乎来自另一个世界......
  • @Neil,OP 从未声明他无法控制应用程序。如果他/她无法控制应用程序的main,你是绝对正确的!如果是这样,我唯一能想到的就是玩 Xmx 和 Xms。
  • 我可以完全控制所有应用程序。在 H2 和 Quartz 的情况下,它是围绕这些库的包装器。这不是我们所说的虚拟机。它实际上是一种 PLC(来自 Beckhoff)。对于一些 Java 应用程序来说,512 mb 的 RAM 是不是有点小内存?

标签: java multithreading memory jvm


【解决方案1】:

从一组单独的进程变为单个进程通常不仅仅是“拨动开关”的问题。它们是根本不同的架构:

  • 属于同一进程的线程共享某些资源(内存空间、文件句柄等),它们可以相互“看到”这些资源;他们可以以一种非常“轻量级”的方式相互通信并相互共享数据;
  • 不同的进程在某种程度上是更“孤立”的单元:它们不能只是“窥视”彼此的内存、文件句柄等,而是必须以“更重”的方式相互通信(例如通过套接字或操作系统提供的其他设施)。

现在,您从一种模型转移到另一种模型的难易程度以及它会为您购买多少实际上取决于特定组件的作用以及它们之间的交互方式。我不熟悉你提到的一些组件,但从你的描述中听起来好像你基本上有一堆相互连接的“黑匣子”,你将无法进行太多的重新架构。

因此,我建议您查看各种组件的文档,看看它们是否允许您在启动时指定 VM 大小(或“堆大小”),然后尝试将组件降至最低他们需要。 (您的记录器进程大概不需要数百兆字节......)

Windows 原则上不应“因为内存不足而关闭进程”。如果它需要将 JVM 堆的位交换进出虚拟内存 [*],它可能会开始像地狱一样咕咕叫。但它实际上不应该关闭进程。另一方面,如果一个给定的 Java 应用程序在尝试从其堆中分配内存时遇到 OutOfMemoryError,它可能会决定关闭(或根据其异常处理作为默认行为关闭)。各种组件的日志表明发生了什么?

[*] 与本机应用程序不同,Java 应用程序不能很好地处理虚拟内存,因为对于 Java,它的内存是一个单独的“堆”,它实际上希望总是被分页。你应该避免分配总堆大小对于您的 JVM,它接近或大于机器中的物理内存量。

【讨论】:

    【解决方案2】:

    我故意不解决 Neil Coffey 的回答已经涵盖的方面。

    因此,这些 Java 应用程序中的每一个都在它们自己的 JVM 中启动(据我所知)。第一个问题是:我能否通过在一个 JVM 而不是四个 JVM 中运行这四个应用程序来降低它们的内存使用量。如果是这样,我应该使用线程来启动这些应用程序吗?

    不,或者不容易(参见 Neil Coffey 的回答)。

    但是您可以通过将命令行参数传递给 java.exe 程序来调整每个 .bat 的 java 内存设置。

    考虑到您的内存设置相当有限,并且假设您至少有 Java SE 6 Update 10,我建议您尝试 G1 垃圾收集器,使用它可以在相对较低的内存设置下获得不错的性能。

    也许尝试传递这样的东西,并根据需要进行调整:

    -Xss64k -Xms128m -Xmx128m -XX:PermSize=64m -XX:MaxPermSize=64m -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:+UseCompressedStrings -XX:+UseCompressedOops
    

    请注意,XX:+UseCompressedOops 仅适用于 x64 JVM,并且它(以及 -XX:+UseCompressedStrings)可能不适用于您,具体取决于您的 JVM 版本。此外,您不会说它是用于生产还是个人使用。如果用于生产,我建议你不要管这两个,只使用 -XX:+UseG1GC` 之前的东西。

    以上是我需要在单台机器上运行多个 Eclipse 实例时使用的设置变体,使用 2GB RAM 构建更大的项目。不幸的是,您的环境有点硬核,但请尝试一次使用这个应用程序,看看您可以压缩和适应多少。

    如果可以,请向我们提供有关您的进程在做什么的更多信息,以便我们可以尝试评估它们需要多少内存。可能,您可以进一步减少堆栈大小和堆大小。我们知道的越多,调整设置时在黑暗中点击的次数就越少。

    除此之外,我应该做的第一件基本事情是降低内存占用,这对于我这样的“真正的”Java 编程来说是相当新的。 H2连接池,重用对象还有什么? Jconsole 和 Xmx 的东西?

    H2 已经相当轻量级了,听起来是不错的选择。

    JConsole 不会帮助您,但您可能想试一试 JVisualVM,它可以帮助您进行一些概要分析。或者,如果您负担得起,则瞄准 JProfiler。否则 Eclipse 有一个很好的内存分析器。

    可能很天真,但我真的认为,嘿,GC 会为我处理“一切”。可能不会? =)

    这不是魔法,它只是回收未使用的对象。如果您有对它们的引用,它就无法知道您是否需要它们。因此,要么确保引用不保持活动状态(通常通过保持集合或相互链接的复合对象),要么如果您需要长期存在的引用,则可能查看弱引用或软引用(或缓存实现)。

    编辑:HMI 后端使用 Jetty 网络服务器。此外,所有代码要么是开源的,要么是由我构建的。

    给我们更多细节,我们可以进一步挖掘。


    您可以做的另一件事是查看替代 JVM。嵌入式系统有一些,它们显然具有相当受限的环境。


    根据调度作业的复杂性,您可以推出自己的调度程序,而无需依赖 Quartz。它不是特别重量级,但如果您需要压缩每个 MB,那将是您列表中的第一个元素,我会尝试摆脱它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-02
      • 2011-08-22
      • 2014-09-20
      • 1970-01-01
      • 2011-10-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多