1

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

这四个 Java 应用程序是,

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

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

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

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

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

编辑 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 位系统。它有望用于生产用途(或者我遇到了麻烦)。

4

2 回答 2

4

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

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

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

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

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

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

于 2012-06-12T19:31:45.570 回答
1

我故意不解决尼尔科菲的回答已经涵盖的方面。

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

不,或者不容易(见尼尔科菲的回答)。

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 Web 服务器。此外,所有代码要么是开源的,要么是由我构建的。

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


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


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

于 2012-06-12T23:52:47.020 回答