Kiedy i dlaczego klasa Pool jest potrzebna do przechowywania obiektów?

12

Studiowałem opengl es i przykładem, który widziałem, było użycie klasy „Pool” do śledzenia zdarzeń dotykowych i klawiatury.

Czy ktoś mógłby wyjaśnić, w jaki sposób i dlaczego potrzebna jest klasa basenowa. Z tego, co czytałem, miało to coś wspólnego z odśmiecaniem pamięci i ograniczaniem liczby tworzonych klas wejściowych.

To wszystko wydaje mi się trochę abstrakcyjne, więc jeśli ktoś mógłby wyjaśnić, co się dzieje, byłbym wdzięczny, wkleiłem tutaj kod:

    public Pool(PoolObjectFactory <> factory, int maxSize) {            
        this.factory = factory;         
        this.maxSize = maxSize;         
        this.freeObjects = new ArrayList < T > (maxSize);     
    }  
         
    public T newObject() {        
        T object = null ;        
        if (freeObjects.isEmpty())            
            object = factory.createObject();        
        else             
            object = freeObjects.remove(freeObjects.size() - 1);        
            return object;     
    } 

    public void free(T object) {         
        if (freeObjects.size() < maxSize)             
            freeObjects.add(object);     
    }

    PoolObjectFactory <TouchEvent> factory = new PoolObjectFactory <TouchEvent> () {
     
    @Override     
    public TouchEvent createObject() {         
         return new TouchEvent();     
    } 

    Pool <TouchEvent> touchEventPool = new Pool <TouchEvent> (factory, 50); 
    TouchEvent touchEvent = touchEventPool.newObject(); 
    . . . do something here . . . 
    touchEventPool.free(touchEvent);

Dzięki!

Mathacka
źródło

Odpowiedzi:

17

Pule są używane, gdy liczba obiektów gwałtownie się zmienia i są wykorzystywane do zmniejszenia ilości alokacji pamięci i odśmiecania.

Za pomocą puli standardowy nowy Object (), który przydziela nową pamięć, zostaje zastąpiony wyciąganiem już przydzielonego obiektu z puli. Jest to znacznie szybsze, nawet jeśli przejdziesz i zresetujesz wszystkie zmienne w starym obiekcie do wartości domyślnych.

Jeśli tworzysz nowy element za każdym razem, gdy masz ogromne koszty ogólne, pamięć musi być przydzielona dla każdego obiektu. Również dlatego, że tworzysz tak wiele obiektów, musisz je często czyścić, co powoduje, że bardzo często uruchamiany jest moduł wyrzucania elementów bezużytecznych.

Typowym przykładem są pociski.

W przypadku FPS na ekranie może być 0 pocisków, następnie 1000 w następnej sekundzie, a następnie 0 ponownie w następnej sekundzie. Jeśli miałbyś stworzyć nowy pocisk dla każdego wystrzelonego, stały przydział pamięci byłby niezwykle intensywny. Ponadto moduł wyrzucający elementy bezużyteczne musi śledzić wszystkie te wystąpienia i okresowo czyścić, co zajmuje jeszcze więcej czasu.

Jeśli masz pulę 5000 pocisków i aktualizujesz i współpracujesz tylko z tymi, których nie ma na liście freeObjects, masz tylko 5000 całkowitych przydziałów, bez względu na to, jak długo trwa pożar, zamiast 1 przydziału na pocisk. Również moduł wyrzucania elementów bezużytecznych musi działać dopiero po zakończeniu jakiejkolwiek możliwości walki z ogniem. Interakcja z pamięcią jest bardzo wolna, więc ma to ogromny wpływ na wydajność i zapewnia równomierne rozłożenie obciążenia, zapobiegając zacinaniu się liczby klatek na sekundę.

ClassicThunder
źródło
Więc myślę, że klasa basenów dla efektów cząsteczkowych byłaby niezwykle istotna, prawda?
matacka
Tak, właśnie dla tego rodzaju puli sytuacji zostały zaprojektowane.
ClassicThunder
Czy lepiej jest mieć klasową pulę własnych obiektów lub korzystać z fabryki? Tj. Object.getObject () vs ObjectFactory.getObject ()