Limity pamięci przeglądarki przy przetwarzaniu plików
Mój plik ma tylko 15 MB. Dlaczego karcie zabrakło pamięci?
Plik na dysku to wersja skompresowana
Całe nieporozumienie w jednym zdaniu: liczba, którą widać w menedżerze plików, to rozmiar skompresowanych danych, a niczego nie da się przetwarzać, dopóki pozostaje skompresowane. Żeby zmienić rozmiar obrazu, skompresować go ponownie, przekonwertować albo przeanalizować, trzeba go najpierw zdekodować do surowych pikseli — a surowe piksele są ogromne.
Arytmetyka jest prosta. Piksel w pamięci zajmuje zwykle cztery bajty — czerwony, zielony, niebieski i alfa. Zdjęcie 4000 × 3000 to dwanaście milionów pikseli, więc zdekodowana bitmapa waży około 48 MB. JPEG, z którego powstała, mógł mieć 4 MB. Plik urósł dwunastokrotnie, zanim jakakolwiek praca się zaczęła.
| Wymiary | Piksele | Zdekodowana bitmapa |
|---|---|---|
| 1920 × 1080 | 2,1 miliona | około 8 MB |
| 4000 × 3000 | 12 milionów | około 48 MB |
| 6000 × 4000 | 24 miliony | około 96 MB |
| 10000 × 10000 | 100 milionów | około 400 MB |
A jedna kopia nigdy nie wystarcza
Realistyczny potok przetwarzania trzyma naraz kilka kopii: skompresowane bajty wejściowe, zdekodowaną bitmapę źródłową, bitmapę wyjściową w nowych wymiarach, wewnętrzne bufory kodera i skompresowany wynik. Narzędzie, które pokazuje jeszcze podgląd, trzyma kolejną. Dla opisanego wyżej zdjęcia 4000 × 3000 szczytowe zużycie pamięci od dwustu do trzystu megabajtów jest zupełnie normalne — przy pliku, który wyglądał na 4 MB.
Rasteryzacja PDF zachowuje się tak samo, strona po stronie: strona A4 wyrenderowana w 300 DPI to mniej więcej 2480 × 3508 pikseli, czyli około 35 MB po zdekodowaniu, a narzędzie renderujące kilka stron naraz mnoży tę wartość. Z wideo jest jeszcze gorzej, bo dekoder musi trzymać w pamięci kilka klatek odniesienia jednocześnie.
Gdzie leżą prawdziwe pułapy
- Budżet pamięci karty ustala przeglądarka, a nie witryna, i jest on mniejszy niż pamięć zainstalowana w komputerze. Kurczy się dodatkowo, gdy inne karty mają dużo pracy.
- Moduły WebAssembly zbudowane dla powszechnego 32-bitowego modelu pamięci mogą zaadresować najwyżej cztery gibibajty, a przeglądarki często pozwalają na wyraźnie mniej na jedną instancję.
- Pojedyncze bufory mają własną maksymalną długość, znacznie niższą niż cała pamięć, z której strona może korzystać.
- Mobilne systemy operacyjne zabijają kartę, która zanadto urośnie — bez ostrzeżenia i bez błędu, który strona mogłaby przechwycić.
- Pamięć graficzna to osobna, mniejsza pula. Canvas większy niż maksymalny wymiar dopuszczany przez platformę po prostu się nie uda, niezależnie od tego, ile pamięci systemowej jest wolne.
Żadna z tych granic nie jest opublikowana jako jedna liczba, którą można sprawdzić, bo zależą one od przeglądarki, jej wersji, urządzenia i tego, co jeszcze działa. Na tym polega prawdziwa trudność: narzędzie nie ma jak zapytać, ile pamięci wolno mu użyć.
Dlaczego na telefonach limity są najostrzejsze
Telefony mają mniej pamięci fizycznej, nie mają pliku wymiany w rozumieniu desktopowym i mają system operacyjny, który agresywnie odbiera pamięć procesom w tle. Karta przeglądarki staje się procesem w tle w chwili, gdy odpowiadasz na wiadomość. Przeglądarki mobilne trzymają więc ciaśniejsze budżety i szybciej porzucają kartę, a takie porzucenie wygląda dla ciebie nie jak błąd, tylko jak przeładowanie strony i utrata pracy.
Praktyczny wniosek jest taki, że zadanie, które kończy się na laptopie, może być niewykonalne na telefonie z tym samym plikiem. To nie jest wada narzędzia. To granica sprzętu, a uczciwą reakcją jest powiedzieć o tym przed startem, a nie wysypać się w połowie.
Jak zachowuje się porządnie napisane narzędzie
- Szacuje zużycie pamięci na podstawie zdekodowanych wymiarów, zanim cokolwiek zaalokuje, i odmawia zadania, które ewidentnie się nie zmieści.
- Na urządzeniu o ograniczonych zasobach przetwarza jeden plik naraz, zamiast puszczać całą partię równolegle.
- Przekazuje bufory między stroną a jej wątkami roboczymi, zamiast je kopiować, więc duży plik nie istnieje w dwóch egzemplarzach.
- Zwalnia każdy wynik zaraz po zapisaniu i unieważnia tymczasowe adresy URL, które inaczej trzymałyby dane przy życiu.
- Tam, gdzie format na to pozwala, przetwarza strumieniowo strona po stronie albo klatka po klatce, zamiast wczytywać cały dokument do pamięci.
- Ogranicza liczbę pikseli, którą w ogóle przyjmie — i to właśnie powstrzymuje mały plik rozwijający się do gigantycznego canvasu przed położeniem karty.
Co zrobić, gdy zadanie się nie powiedzie
- Zamknij inne karty. Konkurują o ten sam budżet, a przeglądarki nie dzielą go sprawiedliwie.
- Przetwarzaj mniej plików naraz. Kolejka jednoelementowa jest wolniejsza i ma znacznie większe szanse dobiec do końca.
- Najpierw zmniejsz wymiary. Skrócenie dłuższej krawędzi o połowę czterokrotnie obniża zużycie pamięci, a często i tak było tym, o co ci chodziło.
- Podziel duży PDF i przetwórz części osobno.
- Do największych zadań przesiądź się na komputer stacjonarny. To nie porażka przetwarzania lokalnego, tylko właściwe użycie sprzętu, który masz.
- Zrestartuj przeglądarkę, jeśli karta jest otwarta od kilku dni. Długo żyjące karty gromadzą pamięć, którą przeładowanie zwalnia.
Granica każdego oszacowania
Przeglądarki udostępniają tylko zgrubną wskazówkę o dostępnej pamięci, a niektóre nie udostępniają nic. Każda liczba, którą pokazuje lokalne narzędzie, jest więc szacunkiem zbudowanym z wymiarów samego pliku i ostrożnego modelu potoku przetwarzania, a nie odczytem z systemu operacyjnego. Przydaje się przy decyzji, czy w ogóle próbować. Nie jest obietnicą, że zadanie się zakończy, bo czynnik decydujący — to, co reszta urządzenia będzie robić przez najbliższe trzydzieści sekund — jest dla strony internetowej niewidoczny.
Narzędzia do tego zadania
Źródła
- W3C — WebAssembly Core Specification, memory model
- W3C — Device Memory API, and why the value is coarse
- WHATWG — HTML Standard, transferable objects