在ColdFusion中创建对象的行为

J.T*_*.T. 15 coldfusion

有一次,我有一个理论,即在每个请求上实例化对象而不是让它们驻留在Application范围内是一个巨大的记忆力.由于我对ColdFusion的了解多年来一直在增长,我认为我并不真正理解CF如何处理CF框架的"黑匣子"中的类,所以我将要求它进行社区更正或确认.

我只想抛弃我的想法:

  1. CFC被编译成一个类,该CFC中的每个方法都被编译成一个类.
  2. 这些类将驻留在(PermGen)内存中,并可根据CF管理员设置写入磁盘.
  3. 创建新对象或请求模板时,将对源代码进行哈希处理,并将其与编译类存储的哈希进行比较.
    1. 如果匹配,它将在内存中使用已编译的类
    2. 如果编译的类不存在,它将从源代码编译
    3. 如果编译的类存在,但哈希不匹配,则会重新编译.
  4. 另外,无论何时启用可信缓存,ColdFusion都不会对源进行哈希检查以检查差异,并将继续在内存中使用已编译的类.
  5. 无论何时创建新对象,都会获得一个指向已编译类及其方法类的新指针,并且伪构造函数中会出现任何运行时事件.编辑:此时,我指的是使用createObject并在函数运行之外使用任何"松散"代码.当我说指针时,我指的是为对象的作用域(这,变量,函数变量)分配的内存的引用.
  6. 如果您请求init,则构造函数将运行.此时消耗的内存只是新的引用和伪构造函数和构造函数中设置的任何变量.实际上,您并没有为整个班级的副本占用内存.编辑:对于这一步,我指的是使用new运算符或链接你的createObject().init()旧学校.

这消除了我个人多年来可能听到的巨大谬误,即在每个请求中实例化大型对象都是一个巨大的内存耗尽(由于拥有类的副本而不仅仅是引用).请注意,我并不赞成这一点,单身模式令人惊叹.我只是想确认一下发生了什么,以防止在遗留代码中追逐红色鲱鱼.

编辑:感谢大家的投入,这对我来说是一个非常有用的问答.

Bra*_*ood 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没有"类"的概念.一切都只是一个实例或根本不存在.我不确定"伪构造函数中发生的运行时事件"是什么意思.
  6. 需要说明的是,JAVA构造函数已经在您创建CFC的瞬间运行.CF构造函数可以是可选的,但它对CFC实例消耗的内存没有影响.再一次,我认为你也会不必要地挂在伪构造函数上.这只是组件内部的松散代码,它在创建时运行,并且与堆中分配的内存无关.永远不会复制Java类,它只是实例的模板.

  • 请注意,"巨型CFC"并不意味着"更多内存",只是"巨型".class文件(在磁盘上和PermGen中)但是,坦率地说,PermGen与常规Java堆相比通常很小(我们运行8GB)堆和1GB PermGen).CFC _instance_包含一个hashmap(变量范围),它将使用与代码放入的内存一样多的内存 - 与代码的大小无关.一个重要的注意事项:每个方法实际上是一个(小)Java类的实例,并且这些实例被添加到变量范围 - 方法调用是动态的. (2认同)