Ошибка нехватки памяти в VBScript - PullRequest
4 голосов
/ 23 февраля 2011

У меня есть классическая ASP CRM, созданная сторонней компанией. В настоящее время у меня есть доступ к исходному коду и я могу внести любые необходимые изменения.

Случайно в течение дня, обычно после некоторого длительного использования пользователями, на большинстве моих страниц появляется ошибка «Недостаточно памяти».

Способ создания приложения - все страницы и сценарии извлекают основные функции из файла Global.asp. В этом файле также встраиваются другие глобальные файлы, но представленная ошибка показывает

Недостаточно памяти

WhitherScriptYouTriedToRun.asp Строка 0

Строка 0 является включением для файла global.asp. Как только ошибка возникает, через неопределенное время происходит ее возникновение в течение некоторого времени, но затем она начинает повторяться снова. С тем, как написано приложение, и какими функциями он пользуется, а также с «диагностикой», которую я уже выполнил - похоже, это часто используемая функция, которая удерживает данные, такие как набор записей или что-то в этом роде, а затем не выпускает их должным образом. , Затем другие пользователи пытаются использовать ту же функцию, и в итоге она просто заполняется, вызывая ошибку. Единственный способ эффективно устранить ошибку - перезапустить IIS, перезапустить пул приложений и перезапустить службы SQL Server.

Само собой разумеется, я и мои пользователи раздражаются ....

Я не могу точно определить ошибку из-за фактического сообщения об ошибке, представляющего собой Строку 0 - но оттуда я понятия не имею, где в строках кода 20К это может зависать. Любые мысли или идеи о том, как изолировать или, по крайней мере, указать мне правильное направление, чтобы начать прояснение этого? Есть ли способ для меня, чтобы увеличить размер "памяти" для VBScript? Я знаю, что есть ограничение, но установлено ли оно, скажем ... 512 КБ, и вы можете увеличить его до 1 ГБ?

Вот что я пробовал:

  1. Удаление встроенных операторов SQL в представления
  2. Прохождение нескольких сотен сценариев и обеспечение того, чтобы за каждым OpenConnection & OpenRecordSet следовал соответствующий Close.
  3. Просмотр глобального файла и комментирование любых больших операторов SQL, таких как ApplicationLog (функция, которая записывает выполненный запрос в таблицу).
  4. Некоторые мелкие правки скрипта.

Ответы [ 3 ]

6 голосов
/ 23 февраля 2011

Общая утечка памяти

Вы говорите, что закрываете все наборы записей и соединений, что хорошо.

Но вы удаляете объекты?

Например:

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>

Надеюсь, что это помогло.

3 голосов
/ 23 февраля 2011

Вы смотрели на использование инструмента мониторинга памяти, чтобы увидеть, как происходит фрагментация памяти?Я предполагаю, что возможная причина заключается в том, что какой-то объект размером пытается создать, но в памяти недостаточно места для его хранения в виде одного смежного куска.Представьте, что вам нужно место для хранения объекта, который занимал бы 100 МБ, и хотя может быть несколько сотен мегабайт свободного места, самый большой непрерывный блок составляет 90 МБ, тогда это не подходит.


Инструмент диагностики отладкиv1.1 будет инструментом, в котором статьи Бернарда могут помочь в понимании того, как использовать инструмент.

Другая мысль - это вопрос о том, сколько конкатенации строк в коде?Я помню, где раньше у меня были проблемы с выполнением большого количества операций конкатенации строк, которые высасывали память, что может быть еще одной идеей для рассмотрения.


Да, я мог видеть некоторый шок от такого числапервые несколько раз вы видите это, но потом, если вы понимаете, что делает код, может иметь смысл, почему время от времени зарезервировано так много места.


Я не использовал этов частности, инструмент отладки, но у меня был инструмент, который делал снимок памяти, когда страницы зависали, поэтому я не мог определить, было ли влияние инструмента на производительность или нет.Конечно, в моем случае я использовал аналогичный инструмент в 2004 году, так что прошло несколько лет с тех пор, как мне пришлось исследовать этот тип проблемы.

1 голос
/ 10 августа 2012

Просто добавлю это сюда, но эта проблема заняла много времени. Вот разбивка того, что мы сделали:

  1. Мы взяли весь встроенный SQL и создали представления SQL, каждый оператор SELECT теперь обрабатывается сначала VIEW.

  2. Я взял все SQL INSERT и UPDATE (столько, сколько мог, не нарушая систему) и поместил их в хранимые процедуры.

    # 2 был единственным, что действительно имело большое значение

  3. Прошел несколько тысяч сценариев и убедился, что переменные были правильно утилизированы, а все открытые соединения с БД правильно соблюдались при закрытом соединении и то же самое с Open / Close RecordSet.

  4. Один из медленных убийц делал что-то вроде:

    ID = Request.QueryString ("ID)

вверху страницы. Перед перенаправлением или закрытием страницы всегда есть:

Set ID = Nothing 

или полное удаление вывода.

...