2012-08-25 8 views
6

Piszę prosty parser witryny na PHP 5.2.10.
Przy użyciu domyślnego kodowania wewnętrznego (co jest ISO-8859-1), pojawia się błąd zawsze w tym samym wywołaniu funkcji:Wewnętrzna reprezentacja ciągów w PHP

$start = mb_strpos($index, '<a name=gr1>'); 

Fatal error: Allowed memory size of 50331648 bytes exhausted (tried to allocate 11924760 bytes)

Długość string $ indeksu w tym przypadku było 2.981.190 bytes - dokładnie 4 razy mniej niż PHP próbował przydzielić.

Teraz, jeśli mogę użyć

mb_internal_encoding('UTF-8') 

błąd zniknie. Czy to oznacza, że ​​PHP używa więcej pamięci na ciągi jednobajtowe, które dla wielobajtowych? Jak to możliwe? Jakieś pomysły?

UPD: Wydaje się, że użycie pamięci nie zależy od kodowania: średnia memory_get_usage() jest prawie taka sama z użyciem UTF-8 i ISO-8859-1. Myślę, że problem może być w mb_strpos. Rzeczywiście, indeks $ $ ma kodowanie Windows-1251 (cyrylica), więc zawiera symbole, które nie są poprawne dla UTF-8. Może to spowodować, że mb_strpos spróbuje jakoś przekonwertować lub po prostu użyć dodatkowej pamięci dla niektórych potrzeb. Postaram się znaleźć odpowiedź w źródłach mb_strpos.

+0

może pomóc? http://www.php.net/manual/en/function.mb-strpos.php#81722 –

+0

czy rozważałeś ulepszenie swojego PHP? Po pierwsze dlatego, że 5.2 nie jest już obsługiwany, a po drugie, ponieważ zarówno wydania 5.3, jak i 5.4 miały znaczną poprawę wykorzystania pamięci (szczególnie 5.3). Nie jestem pewien, czy te ulepszenia zawierają 'mb_strpos()', ale warto to uaktualnić w każdym przypadku. – Spudley

+0

Uważaj, że aktualizacja jest na dobrej drodze. Wiele rzeczy może mieć wpływ na ... mb_detect_order, użycie 'auto' lub 'pass', żeby wymienić tylko kilka. Użycie 'iconv' może być dobrym sposobem na upewnienie się, że twoje struny są" rozsądne "i pasują do wykrytego/ustawionego kodowania. Chciałbyś profilować i zobaczyć, co robi z tymi 1252 kodami kontrolnymi. Och, zła m-dash. – ficuscr

Odpowiedz

3

Przepraszam, jeśli już myślisz o tych potencjalnych problemach.

W wielobajtowych funkcje łańcuchowe sprawdzi UTF-8 kodowanie błędów i, jeśli są nieprawidłowe znaki, zwraca pusty ciąg lub false (jak w przypadku mb_strpos(): http://www.serverphorums.com/read.php?7,552099

Czy sprawdzanie skutkować dostajesz za pomocą operatora === aby upewnić się, że nie jesteś otrzymaniu false zamiast 0?

funkcja mb_strpos() wykorzystuje mbfl_strpos(), co sprawia, że ​​kopie strun (igła, stóg siana), kiedy musi wykonać konwersje (prowadząc do wzrostu pamięci, jak obserwujesz d): https://github.com/php/php-src/blob/master/ext/mbstring/libmbfl/mbfl/mbfilter.c#L811

Zastanawiam się, czy użycie domyślnego kodowania wewnętrznego (ISO-8859-1) pozwoliło na wszystko, a limit pamięci został osiągnięty, podczas gdy kodowanie utf-8 zostało zwarte z powodu niedozwolone znaki i zwrócone false (która, jeśli zostały testowanie z ==, będzie się wydawać, że funkcja po prostu nie znaleźć dopasowanie.)

warto spróbować :)

+0

Ładne ujęcie! Aby sprawdzić, czy wynik jest "false" lub "0", napisałem funkcję podobną 'assert()', kontrola jest wykonywana ściśle (===). Ale teraz nie rozumiem, dlaczego PHP potrzebuje 4 razy mniej pamięci - w rzeczywistości konwertuje oba argumenty do UTF-8 (a nie 'mb_internal_encoding()'). Dzięki za badania i źródła! ;) – Dmitry