Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Require/Include w celu oszczędzania pamięci
Forum PHP.pl > Forum > PHP
HorriblyBlue
Witam forumowiczów!

Zgodnie z tematem, chciałbym uzyskać informację czy stosowanie include/require (dalej I/R) w "ciele" metody obiektu zaoszczędzi nam chociaż trochę pamięci.
Chodzi tutaj o pamięć, które jest potrzebna do załadowania samego kodu, pytanie z kategorii samego mechanizmu PHP a nie kodowania smile.gif

Prościej: pytanie brzmi, czy PHP podczas kompilacji zawsze i wszędzie wywołuje I/R które zostały w pliku zdefiniowane (tym samym stosowanie I/R pod kątem oszczędzania pamięci jest bez sensu) czy może I/R jest dopiero kiedy dana metoda zostanie faktycznie wywołana?

Przykład (proszę o powstrzymanie się przed wypowiedzami typu "ale kiedy takie coś będzie miało miejsce", będzie wink.gif

Scenariusz 1: Plik z klasą (pełną) ma 1MB, metoda M1 ma 10 linijek kodu, metoda M2 ma powiedzmy 100000 linijek (które zajmują prawie 1MB) - na potrzeby przykładu
Scenariusz 2: Plik z klasą w której każda metoda zamiast kodu ma "include('Method-M1.php');" (plik ma 1KB), "include('Method-M2.php');" (plik ma prawie 1MB) - j/w

Wywołanie 1: PHP wczytuje plik z klasą (1MB), tworzymy obiekt, wywołuje M1 (dla 10 linijek kodu wczytano 1MB kodu)
Wywołanie 2: PHP wczytuje plik z klasą (~1KB), tworzy obiekt, wywołuje M1 (~1KB) - tu moje pytanie, czy PHP wczytał rzeczywiście łącznie ~2KB czy nadal 1MB?

Nie wiem czy pytanie jest jasne i czy nie jest oczywiste wink.gif))

Za każdą odpowiedź z góry dziękuję.
wookieb
Tak ładowanie klas dynamicznie pomaga oszczędzić pamięć. Większość pamięci w aplikacji jest zużywana właśnie na treść plików klas. Dlatego nie rozumiem, jak czasem ludzie mają bezsensowne kontrolery po tysiąc linii gdzie jest 10 akcji. Wtedy rozbija się je na mniejsze pliki. Tak czy siak zainteresuj się autoloaderami.

Dalszego twojego wywodu nie rozumiem.
Stworzenie nowego obiektu nie deklaruje metod od początku. Po prostu siedzą one w pamięci od momentu załączenia pliku z klasa w której się znajdują oraz czekają na swoje wywołania.
Nowy obiekt zużywa pamięci tyle ile potrzeba na zdefiniowanie właściwości nie statycznych jakie są w jego środku + swoje dodatkowe (nazwa klasy, flagi itd)
konole
remove.
wdev
Include sa ladowane podczas parsowania pliku.

Hmm... Czysto teoretycznie, jezeli Cie to interesuje, to mozesz sobie sam sprawdzic uzywajac : memory_get_peak_usage albo po prostu zrobic include z plikiem zawierajacym blad parsowania i sprawdzic kiedy sie wysypie wink.gif Normalne pliki include sa wprowadzane do kodu natychmiastowo, wiec mysle, ze jest podobnie z klasa, ale glowy nie dam.

Inna sprawa, ze jesli bys mial metode, ktora ma 100 tys. linijek to Twoj kod jest naprawde zle skonstruowany... I prawdopodobnie tracisz gdzie indziej duzo wiecej pamieci niz zyskasz na swoim rozwiazaniu. Nie mowiac o tym, ze oszczedzajac na pamieci tracisz na szybkosci wykonywania kodu wink.gif
cojack
Ja już kiedyś z wook'iebem rozmawiałem na temat Autoloader'ów, ja osobiście nie toleruje tego cholerstwa, nie trawię, nie lubię i dla mnie jest to dodatkowy narzut pamięci jaki jest potrzebny do wywołania klasy. Osobiście w swoim fw wczytuje klasy ręcznie, require_once tam gdzie potrzebuje. A takie rozwiązanie jak wypisujesz nie oszczędzi pamięci, bo tak czy siak klasa musi zostać załadowana, czy to nastąpi w miejscu jej wywołania, czy jeszcze przed deklaracją klasy to nie ma znaczenia.

Możesz zrobić plik w którym będą znajdowały się klasy, sam plik będzie ważył parę MB, ale przy wykorzystaniu tego pliku (stajni klas), będziesz miał już wczytane klasy które i tak wymagane są podczas pracy kodu, następnie apc_compile_file, i zobaczysz sam jak drastycznie zmniejszy się zużycie ramu przez aplikację.
wookieb
Cytat(wdev @ 8.04.2011, 14:08:52 ) *
Include sa ladowane podczas parsowania pliku.

Nieprawda. I na całe szczęście.
Zyx
Sensownie napisane automatyczne ładowarki bazujące na mapie klas są niewiele wolniejsze, niż niekorzystanie z ładowania klas w ogóle, za to pozwalają uniknąć mnóstwa błędów i przekleństw, które czasem mogą się ludziom rzucić na mózg smile.gif. Jeśli i to dla nas jest niewystarczające, wystarczy sobie zapuścić jakąś ładowarkę klas ze śledzeniem i przeklikać system, by zgromadzić dane. Wtedy sobie zobaczymy, jakie klasy są ładowane przy każdym żądaniu i możemy je dołączyć ręcznie z pominięciem ładowarki. Jeśli komuś zależy na dalszym przyspieszaniu, od tego jest APC i włączone cache'owanie kodu bajtowego plików.

Warto też zauważyć, że jeśli dołączymy zbyt dużo niepotrzebnych klas, możemy całkowicie roztrwonić nasz zysk wynikający z braku automatycznego ładowania.
HorriblyBlue
Witam forumowiczów,

Jak doświadczenie pokazuje, lepiej jednak samemu sprawdzić smile.gif, dlatego dzielę się wynikami.
Najpierw deklaracja klasy w pliku index.php:

  1. class Test
  2. {
  3. public function M1()
  4. {
  5. echo 'Metoda 1';
  6. }
  7.  
  8. public function M2()
  9. {
  10. echo 'Metoda 2';
  11. require_once('Test_M2.php');
  12. }
  13. }


Plik Test_M2.php zawiera 1,1MB kodu (nieistotne jakiego, nieistotne dlaczego, tak po prostu jest smile.gif ).

Jeżeli do pliku index.php zostanie dodane utworzenie obiektu i wywołanie M1:

  1. $oTest = new Test();
  2. $oTest -> M1();


Dostajemy wyniki:

Szczytowe użycie pamięci (na początku): 0,31 MB
Szczytowe użycie pamięci (na końcu): 0,31 MB

Natomiast wywołanie metody M2:

  1. $oTest = new Test();
  2. $oTest -> M2();


Szczytowe użycie pamięci (na początku): 0,31 MB
Szczytowe użycie pamięci (na końcu): 2,6 MB

(zastanawiające jest, dlaczego po wczytaniu pliku 1,1MB [test wykonywany na takim pliku, zawierał jedynie deklaracje echo "treść....treść"] spowodował dwukrotnie większe zużycie pamięci?)

Wnosek 1: (bardzo) dobrą praktyką jest stosowanie require_once dla kodu zawartego w metodach, ponieważ pomoże to zaoszczędzić pamięć, potrzebną do wczytania kodu php (treści pliku), dodatkowo zachowujemy czystość kodu.
Wniosek 2: deklaracje require/include nie są wywoływane w momencie parsowania skryptu

Cytat
Inna sprawa, ze jesli bys mial metode, ktora ma 100 tys. linijek to Twoj kod jest naprawde zle skonstruowany... I prawdopodobnie tracisz gdzie indziej duzo wiecej pamieci niz zyskasz na swoim rozwiazaniu. Nie mowiac o tym, ze oszczedzajac na pamieci tracisz na szybkosci wykonywania kodu


Zdaję sobie sprawę, że aplikacja/klasa/metoda(!) mająca 100 tyś. linii kodu może wskazywać na złe podejście do programowania (np. powielanie sekcji kodu itepe), dlatego zaznaczyłem, że jest to sytuacja hipotetyczna.
Zyx
Proponuję jeszcze, byś zapętlił sobie wywołanie takiej metody i dla odmiany zmierzył czas.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.