6

我在 ColdFusion 中编写了一个数据库加载脚本,但遇到了脚本慢慢耗尽内存的问题。我已经使用 <cfthread> 将每个表加载拆分到自己的线程中,并且当内存低于 50% 时调用垃圾收集器(确保在 gc() 调用之间有 30 秒以防止垃圾收集器占用内存) .

我创建了一个 CFC 来保存脚本所需的所有查询。该脚本调用相应的 CFC 函数,然后返回查询,其中一些大小超过 2 MB。当我在活动线程的内存页面的详细信息视图中查看服务器监视器时,看起来我的 CFC 将查询的副本保留在内存中,即使我对查询变量进行了 varscoped 并且变量最后超出了范围的功能。此外,我在线程的内存中有一份查询副本。所以我只剩下内存中查询的两个副本。真的是这样吗?如果是,我怎样才能从内存中删除一份查询?

4

2 回答 2

11

这里有很多潜在的问题,但我会尝试强调一些最重要的事情供您考虑:

  1. 为什么是线程?你需要线程吗?在某个时刻,您可能为了自己的利益而修修补补过多。
  2. 手动强制垃圾收集不一定是个好主意。调整 JVM 以自动执行其垃圾收集,但也不要过度。垃圾收集往往很昂贵,如果运行过于频繁,可能会影响应用的性能。
  3. 你是如何实例化你的 CFC 的?如果您在每次查询请求时都实例化 CFC,那么随着时间的推移,您将遇到 RAM 问题,由于 CFC 太快地加载到 RAM 中而导致垃圾收集跟不上,导致内存泄漏缓慢。你最好的选择是让它成为一个单例。(即,将其设置为应用范围)。
  4. 请注意,一旦变量停止使用,对变量进行 var 作用域(据我所知)不会自动释放内存。内存仍然保留,尽管它可能以某种方式被标记为短命一代的一部分,以便(可能?)更快地清理它。但这并不能保证任何事情。
  5. 如果您正在查看活动线程,则查询也可能在请求结束之前不会被清除 - 不一定是函数调用结束。似乎不耐烦会促使您期望查询在函数调用完成后立即终止。
  6. ColdFusion查询是按引用传递的,而不是按值传递的。应该不可能在内存中获得 2 个查询副本,除非您以某种方式使用 duplicate() 或类似的函数来显式复制查询。

该查询可能会从您的 cfreturn 语句返回一个指向查询的指针。在所有进程完成引用它之前,不会清理该查询。因此,如果它将查询传递给其他进程,则不会将该查询从内存中清除。例如,如果您将该查询设置为会话变量,则该指针在该会话变量消失之前不会去任何地方,无论您尝试强制垃圾收集的频率如何。

只需考虑几件事。

于 2010-03-02T19:20:30.163 回答
0

我在处理大型数据插入时遇到了类似的问题,其中每一行都需要涉及多个 CFC 的大量处理。似乎 <cfquery> 创建的 JDBC ResultSet、Statement 和 Connection 引用一直保留到请求结束。这意味着将查询变量归零对内存使用没有影响。我解决这个问题的方法是对 CFC 函数进行网关调用以处理 100 行,然后该函数对接下来的 100 行等进行另一个网关调用,直到处理完所有行。因为每个单独的网关调用实际上都退出了,所以它释放了它的所有句柄,并且内存得到了恢复。

于 2010-03-09T20:38:47.580 回答