【问题标题】:Java long running timer is being consumed by GCGC 正在消耗 Java 长时间运行的计时器
【发布时间】:2015-11-27 14:26:17
【问题描述】:

我有一个 java.util.Timer,我正在安排 TimerTasks,它每 24 小时在凌晨 3:00:00 运行一次,但是在 5-8 天后,计时器被 GC 消耗,我的所有任务都被取消,因为计时器实例不再存在。

如何防止这种情况发生?

我用:

t.schedule(timerTask, date);

然后任务自己再次启动(任务执行时也调用方法再次调度该任务)

定时器是这样定义的:

public static Timer t = new java.util.Timer();

【问题讨论】:

  • 只有在没有可达的引用时,定时器才会被 GC 消耗。除了初始化之外,您是否随时为 t 分配新值?

标签: java timer task long-integer


【解决方案1】:

如果 Timer 是这样声明和创建的:

    public static Timer t = new java.util.Timer();

那么我认为只有两种情况Timer可以被垃圾回收:

  1. 在您的应用程序中,某处正在为 t 分配一个新值,导致之前的值无法访问。

  2. 包含t 声明的类已无法访问并已被卸载。

到目前为止,第一种情况最有可能发生,并且有一种简单的方法可以避免这种情况。将声明更改为:

   public static final Timer t = new java.util.Timer();

只有当您的应用程序(或者可能是它正在使用的框架)使用本身变得无法访问的类加载器动态加载类时,第二种情况才合理。

【讨论】:

  • 我 100% 确定没有任何东西可以为计时器分配新值。
  • 即便如此,将声明更改为final,以便编译器知道不应为其分配任何内容。如果更改后仍然存在问题,那么您就知道问题是其他问题。
  • 我创建了新的 Timer 类,它基本上是一个扩展 java.util.Timer 的类,但我添加了 public void finalize()... 方法,所以我知道垃圾收集器何时吃掉计时器吃晚饭。
  • 你听从我的建议了吗?
  • 不,因为我无法将其更改为最终版本,因为这个烦人的错误我不得不为我的应用程序创建来自另一个类的所有任务的“重启”命令,所以我不能让它最终因为我有控制台命令重新启动计时器和所有计划任务。
【解决方案2】:

static 变量是class 的一部分,它们在其中被定义并在加载类时被初始化。 GC 可能会在某个时候决定(尤其是当内存不足且挂起操作需要更多内存时)卸载不再需要的类。这就是你在这里可能发生的事情。您可以尝试将 Timer 对象创建为类的非静态成员,该类保证具有仍被 GC 引用的实例。

【讨论】:

  • 嗯,是的,但是只有在无法访问的情况下才会卸载一个类。这就是“不再需要”的真正含义。并且一些如果(可访问)类中的某些代码可以使用该静态,那么包含该静态的类将是可访问的。
猜你喜欢
  • 2013-05-16
  • 2016-12-22
  • 1970-01-01
  • 2014-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-22
相关资源
最近更新 更多