
2009
Pamięciożerny WordPress – memory exhausted, zbyt mały memory_limit
WordPress ma to do siebie, że nie dba zbytnio o ograniczenie zużycia pamięci. Niestety, przy dodaniu większej ilości wtyczek (większej niż 5-7) zaczynają się problemy z wykorzystanym limitem pamięci.
Błędy pojawiają się najprędzej w panelu administracyjnym, co czynnie uniemożliwia poprawną pracę z systemem.
[11-Sep-2009 15:35:01] PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 170031 bytes) in /home/.../wp-includes/wp-db.php on line 501 |
Plugin WP-Memory-Usage pokazuje ile z dostępnej pamięci jest w użyciu.
Przyczyny
Co może być przyczyną takiego stanu rzeczy, i czy możemy coś z tym zrobić?
Główną przyczyną jest funkcja inicjująca init oraz poprzedzające ją plugins_loaded i widgets_init. Funkcje te ładują do pamięci wtyczki oraz widgety, inicjują całą aplikację.
Aby sprawdzić jak wygląda ładowanie strony pod względem wykorzystania pamięci możemy posłużyć się wtyczką WP Tuner. Po zainstalowaniu wtyczki przechodzimy do panelu zarządzania wtyczką wybieramy jedno z ustawień Presets: np Analyze Timing. Następnie otwieramy dowolną stronę panelu i przewijamy stronę do samego dołu:
Jak widzimy na screenie ilość użytej pamięci skacze drastycznie do 26MB! po załadowaniu funkcji init do ponad 20MB tylko po załadowaniu pluginów! Dawno nie widziałem takiego marnotrawstwa pamięci 😉
Rozwiązania
Możliwości rozwiązania problemu mamy kilka.
Zacznijmy od najprostszych: zwiększenie limitu pamięci 🙂 Jednak w przypadku, gdy nasz wordpress nie jest postawiony na dedyku mamy małą szansę na możliwość ingerencji w to ustawienie. Możemy napisać @ do admina.
Jeśli natomiast mamy możliwość zmian konfiguracji możemy zastosować kilka wpisów:
php.ini:
;; set new memory limit memory_limit = 64M |
.htaccess:
# set new memory limit php_value memory_limit 64M |
lub w php:
// set new memory limit ini_set('memory_limit','64M'); |
Jak już wspomniałem w przypadku serwera wirtualnego takie zapisy zwykle nie zadziałają. Co nam pozostaje jeśli nie możemy zmienić wielkości limitu? Niewiele… Możemy co najwyżej odchudzić katalog wtyczek, wyłączyć i usunąć te niepotrzebne/nieużywane.
Aby odciążyć generowanie strony bloga możemy (powinniśmy) zainteresować się cache. Wtyczek do cache jest sporo. Najbardziej popularne to: WP Widget Cache oraz WP Super Cache. Pierwsza robi cache samych widgetów, druga natomiast (w zależności od trybu) może zrobić cache wszystkiego 😉
Oczywiście możemy sami zająć się utworzeniem mini-systemu cache. Może mieć to zastosowanie w przypadku używania własnych pluginów. Pokażę na przykładzie.
W stopce mam 2 utworzone przeze mnie kolumny: Czytuję oraz RSS. Czytuję polega na pobraniu odnośników w wybranych kategoriach. Dzieje się to dynamicznie, przy każdym załadowaniu strony. Jednak po co? Przecież nowe linki nie są dodawane tak często. Zatem własny mini-system cache może być jak najbardziej na miejscu.
Domyślnie tworzenie kategorii RSS odbywało się tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | < ?php function rss_footer($rss_channels=array()){ if (!empty($rss_channels)){ foreach ($rss_channels as $channel){ if(function_exists('fetch_feed')){ $limit = ($channel['limit']) ? intval($channel['limit']): 3; $feed = fetch_feed($channel['uri']); printf($feed->get_title()); for($i=0;$i< $limit;$i++){ $item = $feed->get_item($i); printf('<li><a href="http://blog.vokiel.com/">%s</a></li>',$item->get_permalink(), $item->get_title()); } } } } } ?> |
Sama funkcja wywoływana w stopce:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <ul> <li><h2>< ?php _e('RSS'); ?></h2> <ul> < ?php $rss_channels = array( array('uri'=>'http://forum.php.pl/index.php?act=rssout&id=1','limit'=>3), array('uri'=>'http://webhosting.pl/feed/rss/n/8','limit'=>3), array('uri'=>'http://feeds.feedburner.com/nettuts','limit'=>3) ); @include(TEMPLATEPATH . '/rss_footer.php'); if (function_exists('rss_footer')) { rss_footer($rss_channels); } ?> </ul> </li> </ul> |
Aby nasz system nie pobierał kanałów rss za każdym przeładowaniu strony zrobimy małe cachowanie wyników do pliku:
Schemat działania:
1. Sprawdzenie czy istnieje plik cache
2. Jeśli plik istnieje – sprawdzenie czy jest aktualny
3a. Jeśli plik jest aktualny – wczytanie i wyświetlenie
3b. Jeśli plik nie jest aktualny, lub nie istnieje – utworzenie go i wyświetlenie
Zatem do dzieła!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | < ?php function rss_footer($rss_channels=array()){ // ścieżka wraz z nazwą do pliku cache $cache_file_name = dirname(__FILE__).'/../../cache/rss_footer.cache'; $cache_time = 21600; // limit czasu ważności cache if (!empty($rss_channels)){ // sprawdzenie czy plik cache istnieje i czy jest aktualny if (file_exists($cache_file_name) && filemtime($cache_file_name ) > (time() - $cache_time)){ //plik aktualny - pobranie echo file_get_contents($cache_file_name); }else{ //pobranie wyników foreach ($rss_channels as $channel){ if(function_exists('fetch_feed')){ $limit = ($channel['limit']) ? intval($channel['limit']): 3; $feed = fetch_feed($channel['uri']); //dopisanie do cache $cache .= trim($feed->get_title()); for($i=0;$i< $limit;$i++){ $item = $feed->get_item($i); // dopisanie do cache $cache .= '<li><a href="'.trim($item->get_permalink()).'">'.trim($item->get_title()).'</a></li>'; } } } $cache .= "\n".'<!-- Cache created: '.date('Y-m-d H:i:s').'-->'; // zapis do pliku cache file_put_contents($cache_file_name,$cache); // wyświetlenie cache echo $cache; } } } ?> |
Zastosowanie powyższego systemu cache dla RSS i Czytuję zmniejszyło użycie pamięci z 31.5 MB do 26.6MB! Co moim zdaniem, przy takim nakładzie pracy jest wartym uwagi 🙂
A co jeśli ktoś nie może zwiększyć limitu, a do zrobienia cache ma za małą wiedzę? Co pozostaje? Tylko powyłączać przydatne pluginy?
Jeśli sam nie stworzysz mini-cache, to możesz wykorzystać WP Super Cache.
Jeśli to nie pomoże, pozostaje przeniesienie bloga na inny serwer – taki, który umożliwi ustawienie limitu pamięci. Zużycie na poziomie 30MB jeszcze nie jest straszne, niektórzy mają większe 😉
Jestem w trakcie pisania kolejnego posta na temat optymalizacji WordPress’a, zajmę się tam też bardziej front-endem.
Hey, great blog…but I don’t understand how to add your site in my rss reader. Can you Help me, please 🙂
Hi
Just click on the RSS icon in the head section, or use this link: http://blog.vokiel.com/feed
Super-Duper site! I am loving it!! Will come back again – taking your feeds too now, Thanks. 🙂
Świetnie, dzięki za pożyteczne treści do wykorzystania.