在ColdFusion中创建对象的行为

时间:2014-07-08 18:09:08

标签: coldfusion

有一段时间我有一个理论,即在每个请求上实例化对象而不是让它们驻留在Application范围内是一个巨大的记忆力。由于我多年来对ColdFusion的了解不断增长,我不认为我真的理解CF如何处理"黑盒子中的课程。 CF框架,所以我要问这个社区更正或确认。

我只是要抛弃我认为正在发生的事情:

  1. CFC被编译成一个类,该CFC中的每个方法都被编译成一个类。
  2. 这些类将驻留在(PermGen)内存中,并可根据CF管理员设置写入磁盘。
  3. 创建新对象或请求模板时,将对源代码进行哈希处理,并与存储在已编译类中的哈希进行比较。
    1. 如果匹配,它将使用内存中已编译的类
    2. 如果编译的类不存在,它将从源代码
    3. 编译
    4. 如果编译的类存在,但哈希值不匹配,则会重新编译。
  4. 另外,无论何时启用可信缓存,ColdFusion都不会对源进行哈希检查以检查差异,并将继续在内存中使用已编译的类。
  5. 每当您创建一个新对象时,您都会获得一个指向已编译类及其方法的新指针。类和任何运行时事件都发生在伪构造函数中。 编辑:此时,我指的是使用createObject并且有任何"松散"函数外部的代码运行。当我说指针时,我指的是为对象的范围(这个,变量,函数变量)分配的内存的引用。
  6. 如果您请求init,则构造函数会运行。此时消耗的内存只是新的引用和伪构造函数和构造函数中设置的任何变量。实际上,您并没有为整个班级的副本占用内存。 修改:对于此步骤,我指的是使用new运算符或链接你的createObject()。init()旧学校。
  7. 这消除了我个人可能多年来所听到的巨大谬误,即在每个请求中实例化大型对象都是一次巨大的记忆困扰(由于拥有该类的副本而不仅仅是参考)。请注意,我并不赞成这一点,单身模式令人惊叹。我只是想确认一下发生了什么,以防止在遗留代码中追逐红色鲱鱼。

    编辑:感谢大家的投入,这对我来说真的很有帮助。

1 个答案:

答案 0 :(得分:23)

我已经开发了14年的CF并且我从未听过有人声称由于类编译而在每个请求上创建CFC实例消耗了内存。在Java级别,您的CFML代码直接编译为字节码,并作为Java类存储在内存和磁盘上。 Java类不存储在堆中,而是存储在永久生成中,而不是(通常)收集的内存空间。您可以创建该CFC的任意数量的实例,并且不会再使用perm gen空间,但是将分配堆空间以在其存在的持续时间内存储该CFC的实例数据。注意,开源Railo不为方法使用单独的类。

现在,如果你为这个问题创建了大量的CFC实例(或任何变量),那将会在你们年轻一代中产生很多瑕疵。只要在请求完成后没有保留硬引用,那么当下一个次要垃圾收集运行时,这些对象将从堆中清除。这不一定是坏事,但在调整应用程序性能时应始终考虑堆大小和GC暂停。

现在,有理由坚持CFC实例,无论是作为单例模式还是在会话,请求等的持续时间内。一个原因是实际对象创建的开销。这通常涉及磁盘I / O以检查上次修改时间。自从过去以来,对象创建的速度显着提高,但如果您要创建数千个实例,它仍远远落后于原生Java。另一个主要原因是您的对象在应用程序/会话/请求的生命周期内保持状态,例如在用户购物时存储在会话中的购物车。

为了完整起见,我将尝试明确地解决您的观点:

  1. 对于Adobe CF是的,对于Railo,方法是内部类
  2. 是。
  3. 实际上,我并不相信有涉及任何哈希。它全部基于源文件上最后修改的日期时间。
  4. 是的,但是再次没有哈希 - 它只是跳过磁盘I / O来检查上次修改的日期时间
  5. 我不认为"指针"是正确的术语,因为这意味着Java类实际上存在于堆中。 CF使用自定义URL类加载器来加载模板的类,然后创建该类的INSTANCE并将其存储在堆中。我可以理解这可能会让人感到困惑,因为CFML没有" class"的概念。一切都只是一个实例,或根本不存在。我不确定你的意思是"运行时事件发生在伪构造函数"中。
  6. 要清楚,JAVA构造函数已经在您创建CFC的瞬间运行。 CF构造函数可以是可选的,但它对CFC实例消耗的内存没有影响。再一次,我认为你也会不必要地挂在伪构造函数上。这只是组件内部松散的代码,它在创建时运行,并且对堆中分配的内存没有影响。 Java类是从不复制的,它只是实例的模板。