ID tematu: 75604
 |
Wyciek pamięci? |
Autor |
Wiadomość |
Quasi
Excel Expert

Wersja: Win Office 365
Pomógł: 144 razy Posty: 1118
|
Wysłany: 26-02-2024, 09:59 Wyciek pamięci?
|
|
|
Cześć mądre Głowy!
Case study
Mam kod, który generuje w pętli ok. 4000 raportów PDF. Na początku każdej iteracji makro otwiera szablon XLTX i wgrywa, za pomocą filtra zaawansowanego, listę wpłat dla danej osoby… Cały proces trwa ok. 1h, pliki ważą 300-500 KB.
Problem
Przy pierwszych testach na moim komputerze (Windows 64-bit, Excel 32-bit, 16 GB RAM), po wygenerowaniu ok. 60-65% raportów pojawiał się błąd pamięci. Excel jakby się zawieszał na chwilę, a następnie wyświetlał monit.
W rzeczywistości mój komputer przeznacza na Excela ok. 1,1 GB RAM i po przekroczeniu tej liczby, dostawałem zawsze taki właśnie komunikat.. Oczywiście ta zarezerwowana pamięć nieco zwiększała się po każdej iteracji, aż do przekroczenia 1,1 GB.
Literatura
Problem ten jest słabo opisany na polskich forach, ale dużo lepiej wygląda to na grupach anglojęzycznych.
https://stackoverflow.com/questions/14396998/how-to-clear-memory-to-prevent-out-of-memory-error-in-vba
https://www.automateexcel...f-memory-error/
https://www.exceldemy.com...nk-grey-screen/
Ludzie sugerowali zwłaszcza, aby po każdej iteracji zapisywać plik, co miało resetować pamięć RAM. To rozwiązanie nie sprawdzało się jednak w nowszej wersji Excela (u mnie nie działało), nie byłem też fanem takiego podejścia, bo wydłużyłoby to mocno cały proces.
Rozwiązanie…
Problem udało mi się przezwyciężyć w zaskakująco prosty sposób. Instrukcja DoEvents umieszczona na samym końcu każdej iteracji resetuje pamięć RAM. Od teraz wykorzystanie RAM waha się w przedziale 300-600MB, więc z powodzeniem mogę wykonać raporty dla wszystkich osób… na swoim komputerze 😉.
Komputer Klienta
O ile na moim komputerze każdy test wypadał pomyślnie, o tyle na komputerze Klienta... niekoniecznie. Najpierw zrobiliśmy test na 3000 raportach i było OK. Gdy jednak musieliśmy sprawdzić program w warunkach bojowych (4000 raportów), pojawił się niespodziewany zonk...
Tym razem udawało się zrobić 80% raportów i Excel jakby na chwilę się zawieszał, makro przestało się wykonywać, a Excel pozostawiał szary ekran (nie zamknięty plik). Nie było żadnego monitu. Komputer mojego Klienta ma 8 GB RAM.
5 miesięcy później…
Wróciliśmy do tematu tydzień temu. Dziś dostałem informację od Klienta, że wykonał testy. Na tym samym kompie co ostatnio, Excel wciąż przerywa pracę… Na innym komputerze (16 GB RAM), wszystko jednak działa OK. Ja w międzyczasie dokupiłem 16 GB i na moim kompie (32 GB RAM), wszystkie 10 testów zakończyło się sukcesem.
Wnioski i przemyślenia
Zastanawiam się czy problem faktycznie leży w pamięci RAM... No bo skoro Klient ma Excela 365 i 8 GB RAM, to przecież instrukcja DoEvents resetuje RAM po każdej iteracji i cały proces zwykle nie przekracza 600 MB pamięci... Z drugiej strony zastanawiam się, czy to jednak nie jest też kwestia procesora. W trakcie generowania plików PDF, jego zużycie wynosi u mnie ok. 80%.
PS. Kodu udostępnić niestety nie mogę, bo jest już własnością Klienta. Jest to bardziej problem techniczny/sprzętowy niż merytoryczny i zastanawiam się czy na pewno jest to tylko kwestia RAMu.
Dzięki śliczne za wszystkie podpowiedzi! |
_________________ MAKROAPLIKACJE.PL - Automatyzacja Excela Dla Korporacji |
|
 | ID posta:
433818
|
|
|
 |
|
|
|
ple4
ExcelSpec

Wersja: Win Office 2003
Pomógł: 154 razy Posty: 575
|
Wysłany: 26-02-2024, 15:38
|
|
|
Quasi napisał/a: | Instrukcja DoEvents umieszczona na samym końcu każdej iteracji resetuje pamięć RAM |
No to "powymądrzajmy" się ...
Osobiście nie sądzę (zgodnie z zasadą, że "co prawda się na tym nie znam, ale mam na ten temat własne zdanie") by owa "instrukcja" to robiła - gdyby tak było wszystkie i/lub większość programów (tych uruchomionych, jak i działających w tle) zostałaby z pamięci usunięta, a być może nawet system by się zresetował - zależałoby to od sposobu "zerowania" RAM.
Według dostępnych opisów "DoEvents" po prostu chwilowo przekazuje sterowanie do sytemu, który ma wtenczas dostęp do "mechanizmów kontrolujących/sterujących" dany program, czy w ogóle do tego co się dzieje w otoczeniu program-system i następuje przetworzenie wątków/zadań/zdarzeń przez system, które gdzieś-tam się gromadzą.
To co się u ciebie dzieje to, chyba po prostu, nic innego jak zapychanie kolejnych buforów programu a potem systemu, które nie nadążają "z wypróżnianiem się" z danych.
Jeśli już stosować "DoEvents" to np. po każdej instrukcji generującej pdfa, a nie np. przed powrotem pętli do kolejnego obrotu, czyli np. przed "Next".
Chyba w ogóle lepiej by było ustanowić lekką zwłokę czasową poprzez "Timer" lub jakieś inne "Sleep function" - na niektórych kompach generowanie pdfa potrafi trwać do nawet 10 sekund - wystarczy sobie to sprawdzić używając takiego np. "PdfCreatora" ...
... tu abstrahując trochę od tematu, jeśli w systemie jest zainstalowany ów program, to można posłużyć się jego "Com'em" w celu automatyzacji procesu generacyjnego:
Opis systemu automatyzacji:
'https://docs.pdfforge.org/pdfcreator/en/pdfcreator/com-interface/
Przykłady skryptów w katalogu instalacyjnym, np.:
'C:\Program Files\PDFCreator\COM Scripts
... może to "coś" usprawniłoby proces.
Ogólnie, to od siebie widziałbym spowolnienie generowania pdfów, aby dać wytchnąć "buforom" program-system, albo stosowanie jakichś API'szczaków drukujących pdfy na "wirtualną drukarkę pdf", czyli trochę z innego poziomu niż biedulek excel, za wielkich doświadczeń jednak z tym nie mam ... |
|
 | ID posta:
433830
|
|
|
 |
|
|
master_mix
Excel Expert


Wersja: Win Office 365
Pomógł: 1293 razy Posty: 2639
|
Wysłany: 26-02-2024, 21:11
|
|
|
DoEvents, może pomóc, ale czy na pewno zapewni ci to spokojną pracę Twojego projektu ? .... nie sądzę.
A rozszerzanie pamięci RAM maszyny nie ma sensu - poza tym, co za pomysł żeby klienta zmuszać do rozbudowy hardware,
bo ja sobie tak napisałem kod ;)
Sytuacja wygląda następująco:
Nie ma możliwości zarządzania pamięcią w VBA w trakcie działania procesu.
W VBA kod działa w środowisku uruchomieniowym excela - maszyna wirtualna - i jest interpretowany w trakcie wykonywania procesu (procedury),
to środowisko nie ma "wyrafinowanego" systemu zarządzania pamięcią,
jak Java czy .net w których rolę tą pełni rozbudowany mechanizm GarbageCollector (GC)
Najważniejsze aspekty sprawy:
Sprawa rozbija się o zarządzanie tzw, Stertą w pamięci.
java i .net tworzą w pamięci obszar tzw zarządzanej sterty, którą te środowiska są w stanie "manipulować"
VBA korzysta ze sterty natywnej - obsługiwanej przez środowisko systemowe.
W VBA mamy dostępne: Erase dla tablic i Nothing dla obiektów, to całe zarządzanie pamięcią :)
Ale ... Erase i Nothing nie zwalniają pamięci od razu (fizycznie), usuwają jedynie wskaźnik do obiektów i tablic
W momencie zakończenia działania procedury-procesu (pamiętamy: interpretowany w trakcie wykonywania procesu),
na chwilę obsługę przejmuje sys. operacyjny i zwalnia fizycznie pamięć
(wcześniej zarezerwowane obszary przez naszą maszynę wirtualną) w blokach do których nie ma już referencji, czyli ustawia status bloków = Wolny.
(są 3 stany pamięci w sys. : Wolny, Zarezerwowany, Używany)
To właśnie wymusiłeś przez DoEvents, oddając kontrolę windowsowi, który mógł posprzątać.
Quasi napisał/a: | Wróciliśmy do tematu tydzień temu. Dziś dostałem informację od Klienta, że wykonał testy. Na tym samym kompie co ostatnio, Excel wciąż przerywa pracę… Na innym komputerze (16 GB RAM), wszystko jednak działa OK. |
Być może miałeś farta ;)
Excel 32bit może rezerwować i używać pamięć adresowaną max na "odległość" do 2GB
Pamiętajmy jednak o tym, że rezerwacja pamięci dla procesu, musi być w jednym ciągu.
Gdy proces "żąda-wymaga" rezerwacji pamięci o określonej wielkości, musi znaleźć pojedynczy ciągły wolny blok,
który jest wystarczająco duży. Nawet jeśli masz 2 GB wolnego miejsca, może zakończyć się to "porażką", bo już pamięć tych 2GB jest tak "poszatkowana"
że nie ma żadnego ciągłego bloku o wymaganej wielkości. W 64bit, masz większą szansę, ale nie "pewność".
(2GB dla Excel jako aplikacji, maszynki wirtualnej i kodu VBA na tej maszynie)
Quasi napisał/a: | Problem ten jest słabo opisany na polskich forach, ale dużo lepiej wygląda to na grupach anglojęzycznych. |
Nic nie wyjaśnili :)
Zamiast DoEvents użyli Save - > przekazując na moment sterowanie sys. operacyjnemu, to już Twoje DoEvents lepsze ;)
Co do Twojego projektu, to uważam za lekkie szaleństwo tworzyć w jednym procesie 4000 plików pdf.
Nie odważyłbym się tego zrobić nawet w środowiskach zarządzanych.
Pomyśl nad (ładnie to nazywają) batch processing -> podziel pliki na partie, np po 100, aby system nadążył sprzątać. |
_________________
Podejmę współpracę (pracę)
Programowanie C#, Android, iOS, VB.NET, VBA, ASP.NET Core, WPF, Xamarin, Power Platforms, XAML, MVC, LINQ, Entity Framework. Bazy danych SQL Server, Oracle, MySQL, Firebird
Wrocław i okolice …lub zdalnie. |
|
 | ID posta:
433840
|
|
|
 |
|
|
Quasi
Excel Expert

Wersja: Win Office 365
Pomógł: 144 razy Posty: 1118
|
Wysłany: 26-02-2024, 22:09
|
|
|
master_mix napisał/a: |
Co do Twojego projektu, to uważam za lekkie szaleństwo tworzyć w jednym procesie 4000 plików pdf.
Nie odważyłbym się tego zrobić nawet w środowiskach zarządzanych.
Pomyśl nad (ładnie to nazywają) batch processing -> podziel pliki na partie, np po 100, aby system nadążył sprzątać. |
Mam rozwiązanie, które zabezpiecza nas przed tym błędem i pozwala wygenerować raporty niejako "na raty" w kilku sesjach. Po prostu, w panelu operator wybiera numer początkowy i końcowy i raporty generują się tylko dla osób z tego zakresu.
Tylko nie bardzo chcemy się... rozdrabniać, bo ta część jest ostatnim i najważniejszym etapem procesu, który składa się z .... 9 etapów i trwa cały dzień 😀. Chodzi o prawidłowe rozksięgowanie wpłat z 1.5% podatku na subkonta dzieci. Mamy aż 315 000 takich wpłat, a Podopiecznych było w zeszłym roku ok. 4000. 99% celów program rozszyfrowuje w 5min, ale resztę musi już zrobić ludzkie oko/mózg przy pomocy mini-programu. Najważniejszy w tym wszystkim jest czas i skuteczność.
Case study projektu można znaleźć tutaj: https://www.makroaplikacje.pl/fundacja/
Reasumując.
Póki co DoEvents spełnia swoją rolę, aczkolwiek zobaczymy czy sytuacja się zmieni gdy trzeba będzie zrobić np. 6000 raportów. Jeśli Excel zgłosi błąd, podzielimy to na kilka sesji 🙂. |
_________________ MAKROAPLIKACJE.PL - Automatyzacja Excela Dla Korporacji |
|
 | ID posta:
433842
|
|
|
 |
|
|
ple4
ExcelSpec

Wersja: Win Office 2003
Pomógł: 154 razy Posty: 575
|
Wysłany: 27-02-2024, 17:12
|
|
|
1. Trzeba by jeszcze sprawdzić, w którym miejscu kodu 'DoEvents' "działa najlepiej"
2. Spróbuj jeszcze ewentualnie zwiększyć plik wymiany na danym kompie, jeśli jest on ustawiany na sztywno i jeśli administratorzy na to pozwolą (lub w ogóle może ustawić na wielkość zarządzaną przez system) |
|
 | ID posta:
433854
|
|
|
 |
|
|
Rafał B.
ExcelSpec


Wersja: Win Office 2021
Pomógł: 91 razy Posty: 524
|
Wysłany: 27-02-2024, 20:21
|
|
|
Ciekawe czy podział na paczki uruchamiane przez `Application.OnTime`z zerowym czasem też przekazuje na moment sterowanie do systemu operacyjnego. Chociaż i tak nie byłoby w tym raczej żadnej przewagi nad `VBA.DoEvents`.
Ogólnie to DoEvents jest też trochę demonizowane nad wyraz- a 95% płaczu nad tą metodą z biblioteki standardowej, to używanie implicite ActiveSheet, ActiveWorkbook w kodzie w stylu `Range("abc").Value`, `Sheets("xyz").Range...`, który często widujemy nawet wśród powszechnie szanowanych osób na tym forum, zamiast w pełni kwalifikowanych obiektów Range. W dobrym kodzie DoEvents nie powinien robić szkód poza jakimiś rzadkimi przypadkami. W formularzach jest to bardziej skomplikowane, ale czasem nieodzowne, .Repaint niestety nie zawsze działa prawidłowo. Każdy programista VBA musi czasem tego DoEvents użyć, jak działa, to gitara
Ale jakieś WinAPI, na pewno ktoś byłby w stanie wyczarować. I w oparciu o to napisać sobie własną klasę GarbageCollector |
_________________ W erze zaawansowanych narzędzi LLM takich jak GPT 50% problemów użytkowników forum może być efektywnie rozwiązanych przez nich samych za pomocą tych narzędzi. Jednak często bardziej cenią swój czas niż czas tych, którzy oferują tutaj pomoc. |
|
 | ID posta:
433855
|
|
|
 |
|
|
Artik
Artik


Wersja: Win Office 365
Pomógł: 3268 razy Posty: 10790
|
Wysłany: 03-03-2024, 14:34
|
|
|
Rafał B. napisał/a: | Ciekawe czy podział na paczki uruchamiane przez `Application.OnTime`z zerowym czasem też przekazuje na moment sterowanie do systemu operacyjnego. | Tak, przekazuje. Ale... nie masz żadnej gwarancji, że w tym czasie pamięć zostanie natychmiast zwolniona. Obserwując niejednokrotnie Task Manager-a (TM) zauważyłem, że zwolnienie pamięci następowało dopiero po kilku sekundach. Mam świadomość, że TM odświeża się co najmniej po 0,5 sek (zależne od ustawień w TM). Więc zwolnienie pamięci musiało odbywać się później niż ten interwał skoro widzę zmiany dopiero po kilku sekundach. Czas zwolnienia pamięci jest zagadką, czasem to chwila-moment, a czasem dłużej.
Teoretyzując, bo nigdy się w to nie bawiłem, można by przy zakończeniu procedury głównej, wywołać poprzez OnTime procedurę, która zbada (pewnie jakieś API) kiedy nastąpiło zwolnienie pamięci (pętla "obserwująca" zajętość pamięci). Być może będzie trudność w ustaleniu jaką wartość (różnicę w obserwowanych wartościach) należy uznać za zwolnienie pamięci. Kiedy już wykryjemy ten moment dopiero wtenczas znów poprzez OnTime uruchamiać procedurę główną.
Do czego dążę? Czytając ten wątek, już po pierwszych postach przyszło mi do głowy rozbicie duuużej pętli na kilka etapów. Z opisu problemu wynika, że ok. 3000 obrotów pętli wykonuje się bezproblemowo. Dlatego spróbowałbym zbudować pętlę tak, by co np. 1000 obrotów (wydaje się to bezpieczna ilość) pętlę przerwać i poprzez OnTime wywoływać procedurę ponownie. W tym celu, parametry wejściowe pętli pewnie należałoby przechowywać w zmiennych globalnych. Samo wywołanie OnTime nie ustawiłbym na Now(), a raczej na Now() + TimeSerial(0,0,15). 15-sekundowa przerwa zastępowałaby wcześniej wspomnianą procedurę monitorującą zwolnienie pamięci. Strata ok. minuty na procesie trwającym ok. godziny, moim zdaniem, jest akceptowalna jeżeli rozwiązanie działałoby stabilnie(j). Użycie OnTime nie zwalnia nas oczywiście z utrzymania bieżącej "higieny" w pętli, czyli stosowania Nothing, DoEvents, Erase itp. Z moich doświadczeń na przestrzeni lat wynika, że częste użycie DoEvents wpływa na wydłużenie czasu wykonania zadania. Dlatego niejednokrotnie w pętli wstawiam warunek, który zezwala na użycie DoEvents co ileś obrotów.
Artik |
_________________ Persistence is a virtue in the world of programming.
Weryfikator NIP - szybka, masowa weryfikacja w MF i VIES. |
|
 | ID posta:
433971
|
|
|
 |
|
|
master_mix
Excel Expert


Wersja: Win Office 365
Pomógł: 1293 razy Posty: 2639
|
Wysłany: 03-03-2024, 20:01
|
|
|
Artik napisał/a: | Czas zwolnienia pamięci jest zagadką, czasem to chwila-moment, a czasem dłużej. |
Dlatego że windows ma swój własnego managera odśmiecania i ni cholery nie wiadomo kiedy on zadziała
Pamiętać trzeba że w systemie oprócz naszego excela, działają dziesiątki innych procesów , a odśmiecacz jeden.
Rafał B. napisał/a: | Ogólnie to DoEvents jest też trochę demonizowane nad wyraz- a 95% płaczu nad tą metodą z biblioteki standardowej, to używanie implicite |
nieporozumienia mogą być, gdy projekt obfituje w kody związane ze zdarzeniami, coś może pójść wtedy nie tak jak trzeba.
Artik napisał/a: | w pętli wstawiam warunek, który zezwala na użycie DoEvents |
+
Artik napisał/a: | przyszło mi do głowy rozbicie duuużej pętli na kilka etapów |
jest najlepszym rozwiązaniem, na moje oko |
_________________
Podejmę współpracę (pracę)
Programowanie C#, Android, iOS, VB.NET, VBA, ASP.NET Core, WPF, Xamarin, Power Platforms, XAML, MVC, LINQ, Entity Framework. Bazy danych SQL Server, Oracle, MySQL, Firebird
Wrocław i okolice …lub zdalnie. |
|
 | ID posta:
433984
|
|
|
 |
|
|
ple4
ExcelSpec

Wersja: Win Office 2003
Pomógł: 154 razy Posty: 575
|
Wysłany: 04-03-2024, 22:42
|
|
|
Dość zachęcająco wyglądają próby z PdfCreator'em - trzeba tylko odklikać opcje: "Otwórz plik po zapisaniu" i "Pokaż szybkie akcje ..." bo zbędne.
Oczywiście nie próbowane na 4 tys. plików ... więc może to ułuda i mrok ... ale na mniejszych próbkach radzi sobie dość sprawnie - ogólny schemat:
Kod: | Sub słoik_z_powidłami()
Const prn01 As String = "PDFCreator" ' druk. PdfCreator
Const prn02 As String = "Wariatka na Ne01:" ' druk. dom.
Dim opdf As Object, pjob As Object, s As Object, wsh As Object
Set wsh = CreateObject("WScript.Network")
wsh.SetDefaultPrinter prn01
Set opdf = CreateObject("PDFCreator.JobQueue")
opdf.Initialize
'...
s.PrintOut
opdf.WaitForJob (10)
Set pjob = opdf.NextJob
pjob.SetProfileByGuid ("DefaultGuid")
pjob.ConvertTo ("C:\TEMP\" & s.Name & "_prnpdf.pdf")
'Do Until pjob.IsFinished = True: DoEvents: Loop ' ???
Do
Loop Until pjob.IsFinished = True ' ???
'...
opdf.ReleaseCom
Set opdf = Nothing
wsh.SetDefaultPrinter prn02
Set wsh = Nothing
Shell "taskkill /f /im PDFCreator.exe", vbHide ' ???
End Sub |
|
|
 | ID posta:
434021
|
|
|
 |
|
|
Rafał B.
ExcelSpec


Wersja: Win Office 2021
Pomógł: 91 razy Posty: 524
|
Wysłany: 29-07-2024, 16:56
|
|
|
Odświeżam, bo ostatnio przypadkowo w Internecie natknąłem się na podobny problem i tam oprócz przedstawionego w wątku rozwiązania VBA.DoEvents przedstawiono inne obejście problemu przez... zwykły zapis pliku . Może ktoś się zderzy kiedyś z problemem wątkotwórcy, to będzie mógł przetestować czy zapis/zapis kopii faktycznie zwolni pamięć. |
_________________ W erze zaawansowanych narzędzi LLM takich jak GPT 50% problemów użytkowników forum może być efektywnie rozwiązanych przez nich samych za pomocą tych narzędzi. Jednak często bardziej cenią swój czas niż czas tych, którzy oferują tutaj pomoc. |
|
 | ID posta:
436421
|
|
|
 |
|
|
|
Nie możesz pisać nowych tematów Nie możesz odpowiadać w tematach Nie możesz zmieniać swoich postów Nie możesz usuwać swoich postów Nie możesz głosować w ankietach Nie możesz załączać plików na tym forum Możesz ściągać załączniki na tym forum
|
Dodaj temat do Ulubionych Wersja do druku
|
|
Strona uĹźywa plikĂłw cookies.
Kliknij tutaj, Ĺźeby dowiedzieÄ siÄ jaki jest cel uĹźywania cookies oraz jak zmieniÄ ustawienia cookie w przeglďż˝darce.
KorzystajÄ
c ze strony uĹźytkownik wyraĹźa zgodÄ na uĹźywanie plikĂłw cookies, zgodnie z bieĹźÄ
cymi ustawieniami przeglÄ
darki.
SprawdĹş, w jaki sposĂłb przetwarzamy dane osobowe
|