VBScript 内存不足错误

5
我有一个经由第三方公司构建的经典ASP CRM。目前,我可以访问源代码并进行必要的更改。
在一天中的随机时间,通常是用户长时间使用后,我的大多数页面开始出现内存不足错误。
应用程序的构建方式是,所有页面和脚本都从Global.asp文件中提取核心功能。该文件中还嵌入了其他全局文件,但所呈现的错误显示为:
“内存不足 WhateverScriptYouTriedToRun.asp Line 0”
Line 0是global.asp文件的包含行。一旦出现错误,在未指定的时间后,错误就会消失一段时间,但然后开始再次出现。根据应用程序的编写方式、它使用的函数以及我已经完成的“诊断”,似乎是一种常用的函数在保留数据(如记录集)时没有正确释放它。然后其他用户尝试使用相同的函数,最终导致错误。我有效地清除错误的唯一方法是重新启动IIS、回收应用程序池并重启SQL Server服务。
不用说,我和我的用户都感到烦恼......
由于实际的错误消息显示为Line 0,我无法确定错误位置,但是我不知道在20K行代码中它可能卡住了哪里。您对如何隔离或至少指引我开始解决此问题的任何想法或建议?是否有一种方法可以增加VBScript的“内存”大小?我知道有限制,但它设置在512K,您可以将其增加到1GB吗?
下面是我尝试过的事情:
1. 将SQL内联语句转换为视图。 2. 浏览几百个脚本,并确保每个OpenConnection和OpenRecordSet后跟适当的Close。 3. 浏览全局文件,并注释掉任何大型SQL语句,例如ApplicationLog(一个将执行的查询写入表格的函数)。 4. 进行了一些较小的脚本编辑。

我明白没有一个答案能够解决这个问题,而且如果没有知识或者至少查看一些代码,人们很难猜测问题出在哪里。我只是想要一些方向和可能的“诊断”方法。 - RogueSpear00
有时我也会收到HTTP 1.1 / 500错误。 - RogueSpear00
3个回答

8

常见的内存泄漏问题

你说你关闭了所有记录集和连接,这是很好的。

但你是否删除了对象?

例如:

Set adoCon = new
Set rsCommon = new

'Do query stuff

'You do this:
rsCommon.close
adocon.close

'But do you do this?
Set adoCon = nothing
Set rsCommon = nothing

经典ASP中没有垃圾回收,因此未被销毁的任何对象都会留在内存中。

另外,请确保在每个分支中运行您的关闭/无内容代码。例如:

adocon.open
rscommon.open etc

'Sql query
myData = rscommon("condition")

if(myData) then
  response.write("ok")
else
  response.redirect("error.asp")
end if

'close
rsCommon.close
adocon.close
Set adoCon = nothing
Set rsCommon = nothing

在重定向之前,没有关闭/销毁任何内容,因此仅在逻辑的某些分支导致适当的内存清除时才会清空内存。

更好的设计

不幸的是,听起来这个网站的设计并不好。我总是将我的经典ASP结构化为:

<%
    Option Explicit

    'Declare all vars
    Dim this
    Dim that

    'Open connections
    Set adoCon...
    adocon.open()

    'Fetch required data
    rscommon.open strSQL, adoCon
        this = rsCommon.getRows()
    rsCommon.close

    'Fetch something else
    rscommon.open strSQL, adoCon
        that = rsCommon.getRows()
    rsCommon.close

    'Close connections and drop objects
    adoCon.close
    set adoCon = nothing
    set rscommon = nothing

    'Process redirects
    if(condition) then
        response.redirect(url)
    end if
%>
<html>
<body>

<%
    'Use data
    for(i = 0 to ubound(this,2)
        response.write(this(0, i) & " " & this(1, i) & "<br />")
    next
%>

</body>

</html>

希望这些内容能对您有所帮助。

@Tom - 我明白你在第二个例子中的意思。我重新读了一遍,谢谢。再次感谢,我将不得不审查很多脚本以确保遵循这些程序。不过我有一种感觉,许多人并没有遵循这个。 - RogueSpear00
我正在研究过期问题。该网站托管在公司内部服务器上,因此它在我的网络中。目前有大约40-60个用户使用该网站。 - RogueSpear00
@Rogue 你是否使用了任何自定义的VB或C++ COM对象? - Tom Gullen
@Tom - 我一直在阅读不同的论坛等,有人提到ASP只允许您通过一个打开的连接运行一个RecordSet或Query。如果您尝试做多个,则会自动创建更多的连接-但它不会适当地清理或销毁它们。这是真的吗?如果是这样的话,另一个论坛上的OP说要单独实例化每个连接和recordset/query。虽然那似乎没什么问题,但回头去清理代码似乎需要很多工作。有想法吗? - RogueSpear00
@rogue 我会在整个项目中搜索每个对拥有 335 个字段的表格进行 select * 操作,并确保它们都能正确关闭。如果一个受欢迎的页面出现泄漏,就足以导致所有事情都变得混乱不堪。让我知道你处理这个问题的进展如何,我很想看看其中一些页面,你能贴出完整页面吗? - Tom Gullen
显示剩余20条评论

3
你是否考虑过使用内存监控工具来查看内存碎片化的情况?我的猜测可能是某个需要占用100MB的对象尝试被创建,但是没有足够的空间将其存储为一个连续的块。想象一下需要存储一个需要100MB的对象,虽然可能有几百兆字节的空闲内存,但最大的连续块只有90MB,这是无法满足要求的。
Debug Diagnostic Tool v1.1 是一个工具,Bernard 的文章 可以帮助理解如何使用该工具。
另一个想法是代码中有多少字符串连接操作?我记得曾经工作过的地方在执行大量字符串连接操作时出现了内存问题,这可能是另一个需要考虑的问题。
是的,初次看到这样的数字可能会感到震惊,但如果你理解代码正在做什么,那么这种情况可能是有道理的,因为有时需要预留大量的空间。
我没有专门使用过这个调试工具,但是我有一个工具,可以在页面挂起时对内存进行快照,所以我无法确定该工具是否会影响性能。当然,在我的情况下,我在2004年使用了类似的工具,所以已经有几年没有研究过这种问题了。

有什么监控工具推荐吗?我可以整天Google它们,但希望有一些被证明确实有帮助的东西。感谢您的意见。 - RogueSpear00
我注意到一件事 - 我不确定这是否正常 - 但是一旦我开始调试,它在实际进行分析之前,你必须选择要附加的进程。在列表中,它显示了两个w3wp.exe实例 - 其中一个具有24mb / 345mb的私有字节/虚拟字节。听起来很正常...但另一个是196mb / 2048mb。那是2G的虚拟字节!?我曾经听到过Snooki的“哇”声,看到那个数字... - RogueSpear00
当我运行调试工具时,整个Web应用程序会变得非常缓慢,页面响应也很慢。在您的经验中,使用此工具时是否经常发生这种情况? - RogueSpear00

2

我来简单介绍一下解决这个问题花费了很长时间的原因,以及我们做了哪些事情:

  1. 我们将所有内联SQL转换成SQL视图,现在每个SELECT语句都是通过VIEW来处理的。

  2. 我尽量将每个单独的SQL INSERT和UPDATE(在不破坏系统的前提下)放入存储过程中。

    #2是真正产生最大差异的操作

  3. 我们检查了数千个脚本,确保变量被正确处理,并且所有DB打开连接都被正确地关闭,并且同样适用于打开/关闭RecordSet。

  4. 其中一个缓慢的杀手就是像这样做:

    ID = Request.QueryString("ID)

在页面顶部。在重定向或关闭页面之前,总是会执行以下操作:

Set ID = Nothing 

或者完全移除推断。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接