13

我必须编写一个被认为可以“永远”运行的程序,这意味着它不会定期终止。直到现在,我总是编写可以在一天结束时运行和终止的程序。该程序必须进行一些同步,暂停n分钟,然后再次同步。

AFAIK 我目前的实现应该没有问题,理论上它应该运行得很好,但我缺乏任何实际经验。

那么,是否有任何“模式”或最佳实践来编写运行时间非常长的非常健壮且资源高效的 Java 程序?例如运行一个月/一年后可能会出现什么问题?

一些背景:

  • Java:1.7,但编译到 1.5
  • 操作系统:Windows(具体版本还不确定)

提前致谢

4

2 回答 2

9

只是我在编写这种应用程序时必须记住的所有事情的大脑转储。

避免内存泄漏

我有一个应用程序,每天中午运行一次,其中我有一个FileWriter. 我没有正确关闭它,然后我们开始想知道为什么我们的虚拟机在几周后会崩溃。内存泄漏实际上可以以任何形式出现,最常见的例子之一是您没有de-reference适当地使用对象。例如,使用类的字段作为临时存储的方法。通常类会持续存在,引用也会持续存在。这让你有对象,坐在记忆中,什么都不做。

使用正确的调度程序

我在该应用程序中使用了 java Timer,后来我了解到,当另一个应用程序更改系统时钟时,最好使用ScheduledThreadPoolExecutor 。因此,如果您打算让它完全基于 Java,我强烈建议您在 Timer 上使用它,因为这个问题中详述的所有原因。

请注意内存使用情况和您的环境

如果您的应用程序每天都在加载大量数据,并且您有其他应用程序在同一台服务器上运行,那么您可能需要注意时间安排。例如,假设在中午,三个应用程序运行它们预定的操作,我会说在任何其他时间运行它可能是一个聪明的举动。请注意执行代码的环境。

错误处理

您可能想要配置您的应用程序,让您知道是否出现问题,而不会导致应用程序崩溃。如果它每隔几个小时在某个时间运行,这意味着人们可能依赖它,所以我会在你的 Java 代码中添加一个函数,它会向你发送一封电子邮件,详细说明异常的性质。

使其可配置

同样,如果它需要在一天中的不同时间点运行,您不希望将它拉下来几个小时来对您的代码进行一些小的更改。相反,将其移植到 java 属性文件中,或者移植到 XML 配置中(或者实际上,等等)。这样做的好处是您可以在任何人真正注意到差异之前更新您的程序并启动并运行它。

害怕static关键字

那个坏男孩会让对象持续存在,即使你破坏了它们的父引用。如果您不小心,它就是所有内存泄漏的根源。常量很好,你知道不需要改变并且需要存在于项目中才能运行良好的东西,但如果你在项目中将它用于随机值,你很快就会想知道为什么你的应用程序每隔几个小时就会崩溃一次,而不是syncing.

@X86 的道具让我想起了那个。

于 2013-10-10T08:29:26.473 回答
4

内存泄漏可能是最大的问题。确保在您的逻辑迭代后没有长期引用。即使是一个相对较小的对象被永久引用,最终也会耗尽内存(更糟糕的是,如果增长率为 1GB/月,在测试期间将更难检测到)。一种可能会有所帮助的方法是使用分析器的快照功能:在暂停期间拍摄快照,让同步运行几次,然后拍摄另一个快照。比较这些应该显示同步之间的增量,希望应该是零。

缓存维护是另一个问题。缓存的整体大小需要严格限制(而通常你可以在没有短期运行的程序的情况下逃脱,因为所看到的一切都足够小而不会引起问题)。同样,正确地进行缓存失效更为重要——广义地说,在程序仍在运行时,所有被缓存的东西都会在某个时刻变得陈旧,你需要能够检测到这一点并采取适当的措施。这可能会很棘手,具体取决于缓存数据的黄金来源。

我要提到的最后一件事是异常处理。对于短期运行的进程,当遇到异常时让进程终止通常就足够了,因此可以处理问题并重新运行应用程序。对于一个长期运行的过程,您可能需要比这更具防御性。考虑在线程中运行程序的一部分,如果/当它们失败时可以重新启动*。您可能需要一个主管类型的模块,它检查其他一切是否仍在心跳,如果没有,则重新启动它。如果适合您的结构,那么使用actor 风格的库而不是Java 的标准执行程序更容易实现这一点。如果可能的话,你可能想要有钩子(可能暴露在 JMX/MBeans 上)让你稍微修改行为,允许短期黑客/解决方法受到影响,而不必降低流程。虽然这需要相当多的远见才能准确预测几个月后会出现什么问题......

*或者更确切地说,可以在另一个线程中重新启动作业

于 2013-10-10T08:30:51.310 回答