I am running VBA code on a large Excel spreadsheet. How do I clear the memory between procedures/calls to prevent an «out of memory» issue occurring?
jordanz
3434 silver badges11 bronze badges
asked Jan 18, 2013 at 10:32
6
The best way to help memory to be freed is to nullify large objects:
Sub Whatever()
Dim someLargeObject as SomeObject
'expensive computation
Set someLargeObject = Nothing
End Sub
Also note that global variables remain allocated from one call to another, so if you don’t need persistence you should either not use global variables or nullify them when you don’t need them any longer.
However this won’t help if:
- you need the object after the procedure (obviously)
- your object does not fit in memory
Another possibility is to switch to a 64 bit version of Excel which should be able to use more RAM before crashing (32 bits versions are typically limited at around 1.3GB).
answered Jan 18, 2013 at 10:36
assyliasassylias
319k78 gold badges658 silver badges776 bronze badges
5
I’ve found a workaround. At first it seemed it would take up more time, but it actually makes everything work smoother and faster due to less swapping and more memory available. This is not a scientific approach and it needs some testing before it works.
In the code, make Excel save the workbook every now and then. I had to loop through a sheet with 360 000 lines and it choked badly. After every 10 000 I made the code save the workbook and now it works like a charm even on a 32-bit Excel.
If you start Task Manager at the same time you can see the memory utilization go down drastically after each save.
answered Nov 20, 2015 at 14:11
7
Answer is you can’t explicitly but you should be freeing memory in your routines.
Some tips though to help memory
- Make sure you set object to null before exiting your routine.
- Ensure you call Close on objects if they require it.
- Don’t use global variables unless absolutely necessary
I would recommend checking the memory usage after performing the routine again and again you may have a memory leak.
answered Jan 18, 2013 at 10:39
DreamwalkerDreamwalker
3,0324 gold badges30 silver badges60 bronze badges
Found this thread looking for a solution to my problem. Mine required a different solution that I figured out that might be of use to others. My macro was deleting rows, shifting up, and copying rows to another worksheet. Memory usage was exploding to several gigs and causing «out of memory» after processing around only 4000 records. What solved it for me?
application.screenupdating = false
Added that at the beginning of my code (be sure to make it true again, at the end)
I knew that would make it run faster, which it did.. but had no idea about the memory thing.
After making this small change the memory usage didn’t exceed 135 mb. Why did that work? No idea really. But it’s worth a shot and might apply to you.
answered Mar 8, 2019 at 6:53
If you operate on a large dataset, it is very possible that arrays will be used.
For me creating a few arrays from 500 000 rows and 30 columns worksheet caused this error. I solved it simply by using the line below to get rid of array which is no longer necessary to me, before creating another one:
Erase vArray
Also if only 2 columns out of 30 are used, it is a good idea to create two 1-column arrays instead of one with 30 columns. It doesn’t affect speed, but there will be a difference in memory usage.
answered Sep 16, 2017 at 1:11
I had a similar problem that I resolved myself…. I think it was partially my code hogging too much memory while too many «big things»
in my application — the workbook goes out and grabs another departments «daily report».. and I extract out all the information our team needs (to minimize mistakes and data entry).
I pull in their sheets directly… but I hate the fact that they use Merged cells… which I get rid of (ie unmerge, then find the resulting blank cells, and fill with the values from above)
I made my problem go away by
a)unmerging only the «used cells» — rather than merely attempting to do entire column… ie finding the last used row in the column, and unmerging only this range (there is literally 1000s of rows on each of the sheet I grab)
b) Knowing that the undo only looks after the last ~16 events… between each «unmerge» — i put 15 events which clear out what is stored in the «undo» to minimize the amount of memory held up (ie go to some cell with data in it.. and copy// paste special value… I was GUESSING that the accumulated sum of 30sheets each with 3 columns worth of data might be taxing memory set as side for undoing
Yes it doesn’t allow for any chance of an Undo… but the entire purpose is to purge the old information and pull in the new time sensitive data for analysis so it wasn’t an issue
Sound corny — but my problem went away
answered Sep 24, 2015 at 17:46
1
I was able to fix this error by simply initializing a variable that was being used later in my program. At the time, I wasn’t using Option Explicit in my class/module.
answered Feb 18, 2020 at 20:16
TechFanDanTechFanDan
3,2855 gold badges46 silver badges88 bronze badges
Здравствуйте все.
Я разгадал причину с помощью Ваших простых примеров. Спасибо Вам огромное!!!
Проблема крылась не в работе Excel, а в обработке объекта json.
Во вложении приложил файл с json строкой, которая приходит от API, но думаю это особо и не к чему.
Вот как примерно выглядит обработка ответа:
Код |
---|
Dim oRequestList As Collection Dim oRequest As ServerXMLHTTP60 Dim oResponse as Object Dim oItem As Object Dim oRow As Object 'создание асинхронных http-запросов и добавление их в oRequestList For Each oRequest In oRequestList oRequest.waitForResponse Set oResponse = JsonConverter.ParseJson(oRequest.responseText) 'обработка json ответа For Each oItem In oResponse("items") For Each oRow In oItem("rows") ' обработка строки Next oRow Next oItem Set oResponse = Nothing Next oRequest |
Как писал sokol92 «Память освобождается после завершения работы макросов VBA.», действительно, память не освобождается после выхода из цикла, но, позволю себе поправить sokol92’а, память освобождается после завершения работы не макроса, а процедуры/функции, уничтожая все данные, связанные с этой процедурой/функцией и на которые нет ссылок в других местах кода. Моя же проблема заключалась в том, что в коде я не создавал ссылку на массив объектов в цикле, а отдавал это каким-то внутренним силам VBA, в результате чего своими силами я не мог очистить память Nothing’ом. Память не очищалась при помощи Set oResponse = Nothing, потому что была ссылка на коллекцию oResponse(«items»).
Если создать переменную для такой коллекции и передавать ее в качестве коллекции для перебора, а после цикла по oResponse(«items») присвоить ей Nothing, то память очищается при каждой итерации.
Пример:
Код |
---|
Dim oRequestList As Collection Dim oRequest As ServerXMLHTTP60 Dim oResponse as Object Dim oItem As Object Dim oRow As Object Dim oItems As Object Dim oRows As Object 'создание асинхронных http-запросов и добавление их в oRequestList For Each oRequest In oRequestList oRequest.waitForResponse Set oResponse = JsonConverter.ParseJson(oRequest.responseText) 'обработка json ответа Set oItems = oResponse("items") For Each oItem In oItems Set oRows = oItem("rows") For Each oRow In oRows ' обработка строки Next oRow Next oItem Set oRows = Nothing Set oItems = Nothing Set oResponse = Nothing Next oRequest |
Многие, наверное, скажут, что как такое можно было не знать и не понимать, но я не знал
Я запускаю код VBA на большой электронной таблице. Как очистить память между процедурами/вызовами, чтобы предотвратить возникновение проблемы «из памяти»?
Спасибо
Ответ 1
Лучший способ помочь освободить память — это аннулировать большие объекты:
Sub Whatever()
Dim someLargeObject as SomeObject
'expensive computation
Set someLargeObject = Nothing
End Sub
Также обратите внимание, что глобальные переменные остаются выделенными от одного вызова другому, поэтому, если вам не нужна настойчивость, вам не следует использовать глобальные переменные или аннулировать их, когда они вам больше не нужны.
Однако это не поможет, если:
- вам нужен объект после процедуры (очевидно)
- ваш объект не помещается в память
Еще одна возможность — перейти на 64-разрядную версию Excel, которая должна иметь возможность использовать больше оперативной памяти перед сбоем (32-разрядные версии обычно ограничены примерно 1,3 ГБ).
Ответ 2
Я нашел обходное решение. Поначалу казалось, что потребуется больше времени, но на самом деле все становится более плавным и быстрым из-за меньшего количества обмена и доступной памяти. Это не научный подход, и он нуждается в некотором тестировании, прежде чем он будет работать.
В коде сделайте Excel время от времени сохраняйте книгу. Мне пришлось пройти через лист с 360 000 строк, и он сильно задохнулся. После каждых 10 000 я сделал код, сохраняя книгу, и теперь он работает как шарм даже в 32-разрядном Excel.
Если вы запустите диспетчер задач одновременно, вы можете увидеть, что использование памяти резко падает после каждого сохранения.
Ответ 3
Ответ: вы не можете явно, но вы должны освобождать память в своих подпрограммах.
Некоторые советы, однако, чтобы помочь памяти
- Перед тем, как выйти из вашей процедуры, убедитесь, что объект установлен до нуля.
- Убедитесь, что вы вызываете объекты Close, если они этого требуют.
- Не используйте глобальные переменные, если это абсолютно необходимо
Я бы рекомендовал проверить использование памяти после выполнения процедуры снова и снова, у вас может быть утечка памяти.
Ответ 4
Если вы работаете с большим набором данных, очень возможно, что массивы будут использоваться.
Для меня это создало несколько массивов из 500 000 строк и 30 столбцов. Я решил это просто, используя приведенную ниже строку, чтобы избавиться от массива, который больше не нужен мне, прежде чем создавать еще один:
Erase vArray
Также, если используется только 2 столбца из 30, рекомендуется создать два массива с 1 столбцом вместо одного с 30 столбцами. Это не влияет на скорость, но будет разница в использовании памяти.
Ответ 5
У меня была аналогичная проблема, с которой я решил… Я думаю, что это был частично мой код, забивающий слишком много памяти, в то время как слишком много «больших вещей»
в моем приложении — рабочая книга выходит и захватывает другие ежедневные отчеты отделов… и я извлекаю всю информацию, необходимую нашей команде (чтобы свести к минимуму ошибки и ввод данных).
Я прячу их листы напрямую… но я ненавижу тот факт, что они используют Merged cells…, от которых я избавляюсь (то есть unmerge, затем нахожу полученные пустые ячейки и заполняю значения сверху)
Я поставил свою проблему на
a), не смешивая только «используемые ячейки», а не просто пытается сделать целую колонку… т.е. нахожу последнюю использованную строку в столбце и снимая только этот диапазон (буквально 1000 строк на каждом из лист я хватаю)
b) Зная, что отмена только смотрит за последними ~ 16 событиями… между каждым «unmerge» — я помещаю 15 событий, которые очищают то, что хранится в «undo», чтобы свести к минимуму объем памяти (вверх) т.е. перейдите в какую-либо ячейку с данными в ней.. и скопируйте//вставьте специальное значение… Я УВЕРЕН, что накопленная сумма в 30 листов, каждая из которых содержит 3 столбца, может облагать память, установленную как часть для отмены
Да, это не допускает никаких шансов на отмену… но вся цель состоит в том, чтобы очистить старую информацию и вытащить новые чувствительные к времени данные для анализа, чтобы это не было проблемой.
Звук банальный — но моя проблема ушла
- Remove From My Forums
-
Question
-
Hi,
How do you clear all the memory in the variables in the application.
So.. one way was to go through each (global) variable and write…
Array.Clear(name,index,length)
Var2.clear etc…
But in excel VBA you could use the command «END» and that would clear everything, is there something similiar in vb.net? That would be neater. Also I dont want to close the application, the code would still need to be running.
Thanks
Answers
-
-
Marked as answer by
Friday, June 19, 2009 3:55 PM
-
Marked as answer by
-
Jeff,
No therefore it is managed code, the Framework does that for you as objects are finished to have their lifetime.
It is adviced that you don’t do anything to that.
Sometimes a class uses expensive unmanaged resources like pens for drawing.
It is adviced then to force the disposing of those unmanaged resources by calling the dispose method of the class you are using
I am not sure if this was the answer on your question. I have the idea that your question is more about setting fields to zero or something like that.
Success
Cor
-
Marked as answer by
Jeffs_Programs
Friday, June 19, 2009 3:55 PM
-
Marked as answer by
-
Hi,
But in excel VBA you could use the command «END» and that would clear everything, is there something similiar in vb.net? That would be neater. Also I dont want to close the application, the code would still need to be running.
Thanks
Hi,
You could set the text of a BUTTON to RESTART and use the command.>>
Application.Restart()
This will reset all variables to their initial values.
With one button on a FORM try this.>>Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'You could set this property for Button1 in the DESIGN view instead.>> Button1.Text = "Restart." End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Application.Restart() End Sub End Class
Regards,
John
-
Marked as answer by
Jeffs_Programs
Friday, June 19, 2009 3:55 PM
-
Marked as answer by
Дальше эти переменные, в начале очередного цикла я обнуляю следующим образом:
Prem_Lat_V = Worksheets(«Чистый»).Range(«FP1:VZ1»)
KV_Lat_V = Prem_Lat_V
V_Sum_Dog = Prem_Lat_V
V_Sum_Sm = Prem_Lat_V
V_Sum_Other = Prem_Lat_V
Surrender_mas_V = Prem_Lat_V
Massiv_for_RVD_V = Prem_Lat_V
Bonus_Vipl_V = Prem_Lat_V
Тут лист «Чистый» — абсолютно пустой лист.
Вариант с таблицей, в которой бы я изначально проводил вычисления,а потом ее скопом вставлял бы, я продумывал и даже реализовывал частично, но эти самые данные он все равно ведь в этой таблице хранит, то есть по сути также в буфере. А хотелось бы,чтобы он именно куском вставлял в Excel и сразу забывал о том,что вставил.
Добавлено через 3 минуты
Секретного нет ничего)Просто процедура немаленькая, так едваль будет у кого желание в чужом коде копаться не самом лучшем)
Но файл приложил.
А вариант с nothing я пробовал- не меняет ничего,к сожалению(
Добавлено через 1 минуту
Хотя добавить не получилось…118 кб весит txt(
Добавлено через 2 минуты
V_Sum_Dog_with_coeff типа Variant изначально, но в самом начале в нее вставляется пустой диапазон строки, как в своем сообщении чуть выше написал.