有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

无方法参数直接调用cfc时java ColdFusion内存泄漏

我们的记忆力有问题已经很久了。我终于找到了如何复制该问题的方法,但我不知道是什么导致了它,也不知道如何修复它

我们在一个web可访问/控制器目录中有许多cfc,用于处理提交和处理。当直接调用cfc而没有方法参数时,服务器开始消耗内存

例如,像http://www.domain.com/controller/LoginController.cfc这样的URL将在浏览器中运行,直到超时。/CFIDE已被锁定,无法公开访问

因此,cfexplorer不可用(或不应可用)

我们使用FusionReactor监视我们的实例。我们的服务器设置为20GB的堆空间。加载应用程序后重新启动时,内存将在800MB左右运行

在正常流量下,内存将在5GB和10GB之间波动,并定期进行垃圾收集。一段时间后,服务器最终达到98%的容量。它倾向于在那里运行

罚款数小时甚至数天,有时直到交通高峰将其推倒,并发生outofmemory错误。垃圾回收不恢复内存,也不存在活动内存

FusionReactor报告的长时间运行的线程。只有重新启动服务器才能恢复它

使用FusionReactor(我们刚刚安装了FusionReactor,这是我最终了解这个问题的原因),我检查了PermGen内存空间,发现它占了

堆的85%。这看起来一点也不对劲。我执行了内存转储,并通过Eclipse将其加载到MAP中进行分析。我发现内存中有10个对象

测量1.7GB(1.7x10约占总堆的85%)。这些对象如下所示:

Class Name |  Shallow Heap | Retained Heap | Percentage
byte[1769628928] @ 0x4d963b198  ...128.................POST......../controller/LoginController.cfc......../controller/LoginController.cfc........173.14.93.66........173.14.93.66........www.domain.com........443........HTTP/1.1.......;D:\websites\domain\system\controller\Lo...| 1,769,628,944 | 1,769,628,944 |   8.60%

所以我在我们的一台服务器上重新启动了CF。检查FusionReactor,发现没有内存使用。然后转到浏览器,首先调用cfc,如下所示:

http://www.domain.com/controller/LoginController.cfc?method=foo

这导致onMissingMethod处理程序正确启动并重定向到相应的错误页面,而不影响服务器

但后来称之为:

http://www.domain.com/controller/LoginController.cfc

导致页面挂起。FusionReactor报告没有活动请求,即使有一个正在运行,这就是为什么我们无法在问题发生时识别问题。更糟糕的是,刷新内存会使其缓慢增加十分之一的百分比,而没有报告任何活动。服务器上的超时设置为5分钟。我假设它最终会被杀死,然后以1.7GB的速度成为孤儿。这并没有导致服务器停机,只是增加了内存,目前它的内存使用率为3GB,垃圾收集无法恢复任何内容。这似乎解释了为什么随着时间的推移,对这些URL的随机调用会慢慢吞噬并保留内存

接下来,我从多个浏览器选项卡调用URL。这几乎在瞬间将内存增加到98%。FusionReactor现在显示了两个长时间运行的请求,时间为10秒,并且不断攀升,尽管有超过15个浏览器标签在运行。强行切断线似乎没有任何作用。只有重新启动服务器才能解决问题

所以现在我已经明确了这个问题(幻影线程在PermGen堆中创建巨大的孤立对象)以及如何复制这个问题

我不知道直接向cfc提出请求的方式或原因。可能是机器人或偶尔出现奇怪的浏览器行为

所有大型对象都是jrun的实例。servlet。jrpp。ProxyEndpoint

具体是什么导致了此问题,以及如何解决此问题

这是CF9。01运行Java 1.7.0_25的Win2003服务器上的标准

谢谢

Screenshot of MAP analysis of heap dump


共 (3) 个答案

  1. # 1 楼答案

    也许您可以在应用程序中使用onCFCRequest。cfc负责监控这一问题

    它仍然会创建对象,但您可以记录请求,然后CFABORT应该停止请求

    <cffunction name="oncfcRequest" returnType="void"> 
        <cfargument type="string" name="cfcname"> 
        <cfargument type="string" name="method"> 
        <cfargument type="struct" name="args"> 
        <cfif arguments.method IS "">
            <cflog .... />
            <cfabort />
        </cfif>
    </cffunction>
  2. # 2 楼答案

    我知道这代表着你做事方式的巨大转变,但我一直避免让CF产生不必要的CFC。除非他们改变了做事的方式(我上次玩这个版本是在以前),否则直接点击CFC会导致创建一个新实例

    如果你准备进行一个小测试,可以尝试设置一个简单的前端控制器/代理。cfm页面,并将“控制器”内的CFC移至应用范围。当然,还有更优雅的体系结构可以处理它(除了移动到全孔框架之外),但您可以:

    使用应用程序。cfc将某物的实例(如LoginController)设置到应用程序范围内,然后使用一个简单的“invoke.cfm”页面,该页面基本上希望调用这些应用程序范围内的cfc的名称和参数。比如(举个例子):

    <cfsilent>
    <cfset ctlName = url.controllerName />
    <cfset methodName = url.methodName />
    <cfset response = "" />
    
    <! - Look up the desired single-cfc controller  ->
    <cfif len(methodName) and structKeyExists( application.controllers, ctlName ) >
      <cfset ctl = application.controllers.ctlName />
    
      <! - Now ask it do to something - note that i'm not validating the method...  ->
      <cfinvoke component="#ctl#" method="#methodName#" argumentCollection="#form#" returnVariable="response" />
    </cfif>
    </cfsilent><cfoutput>#response#</cfoutput>  
    

    请注意,这会导致“控制器”是有状态的,需要考虑线程安全性(但无论如何,应该已经考虑了)

  3. # 3 楼答案

    我相信这是ColdFusion中的一个合法错误,我已经通过他们的错误系统报告了它。这个问题在其他系统上部分重复。例如,在我的MBP上,在Apache上运行CF时,直接CFC调用不会导致内存问题,但会立即导致JRun的“内部服务器错误”页面。因此,出现了一些问题,系统正在以不同的方式处理问题。安威

    多亏@iKnowKungFoo和大量实验,我找到了一个解决方法

    在URL范围中插入“method”键/值似乎可以解决这个问题。需要注意的是,它必须在onRequestStart方法中完成,而不是在onCFCRequest方法中完成。从文件来看,呼叫CFC似乎会直接发送到onCFCRequest,但事实似乎并非如此。所有请求都首先通过onRequestStart方法。当onRequestStart返回时,仅当所需的'method'参数存在时,才会调用onCFCRequest

    因此,在本例中,无论如何都不会调用onCFCRequest,因为“method”参数不存在。下面是立即在onRequestStart中运行的代码:

    <cfif Right(arguments.targetPage,4) IS ".cfc"
          AND NOT StructKeyExists(URL,"WSDL")
          AND NOT StructKeyExists(URL,"method")
          AND NOT StructKeyExists(FORM,"method")>
        <cfset StructInsert(FORM,"method","")>
        <cfset StructInsert(URL,"method","")>
    </cfif>
    

    这段代码检查请求页面上的扩展名,如果URL和表单范围中都不存在方法参数,它会在这两个范围中插入一个空白的键/值对。对“WSDL”参数的检查就在那里,因为我发现,虽然这段代码工作得很好,但突然之间,我们中断了为数不多的webservices cfc调用。如果呼叫cfc的是WebService。氟氯化碳?WSDL则不需要method参数,CF以不同的方式处理整个过程

    因此,插入空的“method”值会导致在onRequsetStart完成时正确调用onCFCRequest。当使用无效的空方法名调用cfc时,onMissingMethod现在被正确地启动。该方法会迅速处理错误页面请求,并重定向到自定义错误页面

    自从实施此修复程序以来,所有服务器上的内存使用率都从一致的98%下降到了15%。内存图显示了正在使用和收集的内存的预期锯齿。总体性能已从平均1200毫秒的页面请求时间提高到54毫秒,而所有这些请求都不会在后台大量运行

    尽管如此,我还是希望Adobe能够发现并解决这个问题