ColdFusion 9 - 我的线程正在记忆中 - 我怎样才能阻止它?

问题描述:

当CF9应用程序启动时,我开始启动一个特定的线程。它管理一个队列并从队列中取出项目来处理它们。如果没有要从队列中取出的项目,它将sleep()。这个线程可以活几个星期,处理和睡眠等ColdFusion 9 - 我的线程正在记忆中 - 我怎样才能阻止它?

我遇到的问题是,我从队列中采取的项目被保留在堆(看起来像在老一代)很长时间后我完成跟他们。

完整的垃圾回收是由JVM每小时完成的(我可以从jConsole中得知),甚至在运行时,我已处理的项目仍保留在堆中。我可以这样说,因为我做了一个jmap堆转储并使用内存分析工具Eclipse插件进行分析。

因此,这里是我的代码,这是在Application.cfc执行:

<!--- Kick off a new thread and run through the queue ---> 
<cfthread action="run" name="myThread"> 

    <cfloop condition="APPLICATION.threadProcessing eq true"> 

     <cfif APPLICATION.myQueue.hasNext()> 

      <!--- Get next item ---> 
      <cfset tmpItem = APPLICATION.myQueue.next() /> 

      <!--- Ask item to process itself ---> 
      <cfset tmpItem.process() /> 

      <!--- PROBLEM: these 'tmpItem' objects are never cleaned up by the garbage collector! ---> 

      <!--- Then we sleep for an interval - this is to stop us hogging server resources ---> 
      <cfset sleep(2000) /> 


     <cfelse> 

      <!--- Nothing in the queue, so sleep for a while... ---> 
      <cfset sleep(10000) /> 

     </cfif> 

    </cfloop> 

</cfthread> 

如果我使用不正确的范围或某事谁能告诉我?有没有办法强制清理我的临时对象?我推测,调用显式垃圾回收将无法正常工作,因为它无法清理。

当我们从CF8移动到CF9时,这似乎只是一个问题。

任何和所有的帮助表示赞赏 - 我真的想保持这种线程方式,而不是将其作为计划任务或其他东西运行。

谢谢,Ciaran。

+0

在创建新项目时,不允许任务队列在项目耗尽并重新初始化时过期的原因是什么? – 2010-08-26 14:50:01

+0

@Daniel - 线程是真正的问题,所以我可以以某种方式重新启动线程,因为这是持有对象(内存)的东西。这与使用计划任务非常相似。任务启动,然后遍历队列上所有可用的对象,直到完成。然后稍后停止并检查队列。 – 2010-08-27 07:53:24

+0

如果您在每次添加任务时检查线程是否存在,那么您甚至不必使用调度程序。如果它存在,那么你追加它,如果它不存在,那么你产生它......消除了调度的需要。 – 2010-08-27 15:40:37

我可以提供两条建议。其中一个很不错,但另一个非常稳固。

虽然我没有测试过,但我已经被告知可以通过将空字符串分配给它们的变量名称来尽早释放对象到垃圾回收。本质上,你正在减少对象上的指针数量。我只在CF6.1环境中看过这个,所以我真的不确定它是否适用,假设它实际工作。

如果是我,我会研究什么,是一项计划任务。它不会经常运行(我认为最小等待时间是1分钟,IIRC),但应该在任务终止时释放由调用使用的所有内存。基本上,你只需要删除外部循环和sleep(),并以普通调用的方式调用页面。我不完全确定你的队列是如何工作的,但是由于它在应用程序范围内,所以只要你的任务在应用程序树中(或者包含该应用程序文件),你仍然应该能够访问它。

根据您的其他意见,这听起来像这不是共享环境。运行计划任务是否存在其他障碍?

+1

嘿本 - 我试图将对象设置为空字符串 - 没有喜悦。我们拥有这些框,并且我们始终运行计划任务,有时比使用neo-cron.xml文件上的一些XML hackery的Adobe 1分钟限制更少。 现在我已经添加了一个var关键字,即,并且每100个项目中都添加一个显式垃圾回收调用,所以如果这不能解决它,任务可能是下一个要考虑的事情。感谢您的反馈 。 – 2010-08-26 13:58:55

+0

就像我说的,我真的不知道空字符串技巧是否真的起作用。它对我来说看起来很可疑,但我工作的公司的首席技术人员表示它可以在CF6上运行。祝您有明确的GC。 – 2010-08-26 15:35:41

+0

没有明确的GC运气,重写为计划任务,并解决了内存问题。感谢所有的反馈。 – 2010-08-30 08:25:17

您可能想要考虑锁定您对应用程序范围的使用。

+0

我们已经介绍了 - 锁定是由对象本身处理的,hasNext()负责处理它。 – 2010-08-26 13:52:48

+0

自CF6以来,应用程序范围一直是线程安全的。 – 2010-08-26 15:33:48

+0

我推测Aaron的锁定是为了确保队列的一致性 - 在队列中添加和取出时,我拥有相同的命名锁。 – 2010-08-27 07:55:20

如果我试图找到这个底部,我想知道是什么阻止这些对象成为gc的,我会使用hprofHAT来查看阻止它们被阻止的对象gc'd。

内存gc问题的另一个原因,尽管它听起来像它不适用于你的情况,是覆盖Object.finalize()的对象。这是because它们必须由终结器线程处理才能被回收,并且如果它们的创建速度比终结器线程处理速度快,则可能会遇到mem问题。

+0

我提到我使用jmap。创建堆的hprof格式转储。内存分析工具Eclipse与jhat类似,它将CF线程显示为持有所有对象。所以我知道确切的泄漏位置! 我不认为我的对象重写finalize()(至少我不是!),所以我不确定这是否适用。 – 2010-08-26 14:03:35

我的理解是,线程使用堆栈而不是堆,所以线程内没有“垃圾回收”。他们被保留在堆中,因为他们仍然在堆栈中。任何人纠正我,如果我错了。