eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.comp.programming › Opowiadanie o GC
Ilość wypowiedzi w tym wątku: 79

  • 1. Data: 2009-07-27 08:38:18
    Temat: Opowiadanie o GC
    Od: Maciej Sobczak <s...@g...com>

    Jest taki problem.
    Program działający w systemie rozproszonym tworzy lokalnie i
    przetwarza obiekty typu Item. Każdy Item ma swój unikalny
    identyfikator typu long. Item zna swoje id, któro jest znane również
    innym programom działającym w systemie. Te inne programy wpływają na
    stan lokalnych obiektów Item na podstawie ich id.

    Jeżeli program porzuci swój lokalny obiekt Item, to wszystko co
    dotyczy jego id może być później zignorowane. Zwykle porzucanie
    obiektów Item następuje wtedy, gdy i tak nie ma szansy na dalsze
    interakcje dotyczące tego id, ale nie musi tak być.

    Ponieważ przy każdym komunikacie przychodzącym z zewnątrz trzeba jakoś
    znaleźć odpowiedni lokalny obiekt Item, w programie istnieje mapa,
    której kluczem jest long a wartością jest Item (bądź wskaźnik na
    Item), czyli która dla danego id potrafi znaleźć Item.

    Z powodów, które nie są ważne w tej dyskusji, ten projekt jest pisany
    zarówno w C++ jak i w Javie.

    W C++ typ Item ma destruktor, który wyrejestrowuje swoje id z mapy.
    Dzięki temu, jeśli program "porzuci" jakiś obiekt Item (przez co nie
    może już go obserwować i reagować na zmiany jego stanu), to
    odpowiadający mu wpis w mapie jest natychmiast wyrzucany. W
    szczególności, jeśli program używa obiektów Item w takiej pętli:

    for (...)
    {
    Item it;
    // ...
    }

    to w efekcie mapa nigdy nie ma więcej, niż 1 wpis. Zużycie pamięci
    jest wtedy *stałe* (albo ma znaną górną granicę) - dotyczy to również
    bardziej złożonych, ale nadal cyklicznych układów.

    W Javie nie ma destruktorów, ale jest GC. Jeśli program "porzuci"
    jakiś obiekt Item, to w pamięci wisi zarówno obiekt Item, jak i
    odpowiadający jego id wpis w mapie. Wyciek.
    Na szczęście są słabe referencje, ale uwaga - Item jest *wartością* a
    nie kluczem w mapie. W najlepszym razie GC posprząta obiekty Item, ale
    wpisy w mapie pozostaną, przez co mapa i tak puchnie w nieskończoność.
    Wyciek.
    Można pomyśleć o podpięciu się pod finalizator, ale w opinii
    szanowanych obywateli jest to robienie wiochy. Zamiast tego doradzono
    mi zrobić *dodatkowy wątek*, który będzie okresowo jeździł po mapie i
    wywalał wpisy, których wartości się wyzerowały (czyli te wpisy,
    których obiekty Item zostały posprzątane przez GC).
    To rozwiązanie *prawie* działa, ale ma takie dwie przykre cechy:
    * Komplikuje projekt wymuszając istnienie dodatkowego wątku.
    * Wprowadza dodatkowe wartości konfiguracyjne służące do strojenia
    pracy tego wątku (okres skanowania).

    Piszę *prawie*, bo pomiędzy posprzątaniem obiektów Item (hint: to się
    dzieje dopiero wtedy, gdy GC jest wystarczająco zestresowany, żeby się
    w ogóle ruszyć - co następuje akurat wtedy, gdy *zaczyna brakować
    pamięci*) a skanem mapy jest pewien odstęp czasu, kiedy niepotrzebne
    już wpisy w mapie *nadal* zajmują pamięć, zmniejszając efektywnie pulę
    dostępnej pamięci. To powoduje, że przy dalszej pracy programu GC
    szybciej będzie zestresowany i znowu coś tam posprząta, ale przez nowe
    wiszące wpisy w mapie i tak zostawi jeszcze mniejszą pulę wolnej
    pamięci. Ostatecznie program wylatuje na jej braku, chociaż z
    projektowego punktu widzenia może nigdy nie używać więcej, niż jednego
    obiektu Item.
    Oczywiście zmiany okresu skanowania mapy wpływają jedynie na
    *prawdopodobieństwo* poprawnego działania całego programu i nigdy nie
    można tej poprawności *zagwarantować*.

    Ot, taka sobie historyjka. Ale może ktoś znudzony upałami i burzami
    wpadnie na jakiś pomysł, jak to poprawić.

    Jedną z możliwości jest dodatnie do klasy Item funkcji close() i
    uprzejme poproszenie programisty, żeby jej używał. Jest to
    rozwiązanie, którego poziom abstrakcji i wartość projektowa
    odpowiadają językowi C.
    Są inne?

    --
    Maciej Sobczak * www.msobczak.com * www.inspirel.com


  • 2. Data: 2009-07-27 09:30:24
    Temat: Re: Opowiadanie o GC
    Od: Jacek Czerwinski <...@...z.pl>

    Maciej Sobczak pisze:

    > Jedną z możliwości jest dodatnie do klasy Item funkcji close() i
    > uprzejme poproszenie programisty, żeby jej używał. Jest to
    > rozwiązanie, którego poziom abstrakcji i wartość projektowa
    > odpowiadają językowi C.
    No niestety, mnie najbardziej wkurzająca cecha Javy.

    > Są inne?
    >
    1. Eclipse SWT żeby wylądować poprawnie z zasobami zewnętrznymi (zasoby
    GUI które są skończone w systemie) bardzo mocno buduje relację
    rodzicielstwa swoich obiektów programowych. Potem korzystając z tej
    relacji niszczenie rodzica powoduje dzieci itd.

    Obiekty pierwszego poziomu trzeba niestety dispose() czyli plus/minus
    close(), ale jest tego sporo mniej. Oczywiście są zasady i wskazania itd...

    Nie wyczułem jednak w twoim 'opowiadaniu' relacji rodzicielskich. W
    każdym razie pomysł rodziecielstwa obiektów jest częsty, rówież w
    C++/Delphi.

    2. Inna idea Spring JDBC odnośnie często źle zwalnianych zasobów
    (bazodanowych), zamyka je w przedział czasu. Wołasz funkcję (może trwać
    nawet cięzkie minuty, w tym czasie kod apliacyjny wykonywany jest
    callbackami) ale jak sterowanie wróci do ciebie wiesz, że jest posprzątane.

    3. Trzecia idea, też z baz. Pule. Wywołanie 'new' jest jakby tam
    zamknięte, uzywasz metody. Pule przeważnie chętnie by widziały close()
    ale jak nie, to "radzą" sobie (opcjonalnie) na zasadzie
    czasowo/testowej. Pochodne idee występują w twoim opowiadaniu.

    To na razie tyle pomysłów, szkoda że nie orygilanych





  • 3. Data: 2009-07-27 09:40:21
    Temat: Re: Opowiadanie o GC
    Od: Michal Kleczek <k...@g...com>

    Maciej Sobczak wrote:

    [ciach]
    >
    > W C++ typ Item ma destruktor, który wyrejestrowuje swoje id z mapy.
    > Dzięki temu, jeśli program "porzuci" jakiś obiekt Item (przez co nie
    > może już go obserwować i reagować na zmiany jego stanu), to
    > odpowiadający mu wpis w mapie jest natychmiast wyrzucany.

    Moglbys pokazac kod w C++ ktory to robi bez uzycia jakichs smart pointerow
    zliczajacych referencje? Bo ja nie bardzo to widze (ale specem nie
    jestem) - chyba ze wszystkie obiekty Item o tym samym id sa rownowazne -
    tyle ze wtedy nie jest potrzebna zadna mapa.

    > W
    > szczególności, jeśli program używa obiektów Item w takiej pętli:
    >
    > for (...)
    > {
    > Item it;
    > // ...
    > }
    >
    > to w efekcie mapa nigdy nie ma więcej, niż 1 wpis. Zużycie pamięci
    > jest wtedy *stałe* (albo ma znaną górną granicę) - dotyczy to również
    > bardziej złożonych, ale nadal cyklicznych układów.

    Nie widze w powyzszym przykladzie mapy ani pobierania obiektow Item z tejze.

    >
    > W Javie nie ma destruktorów, ale jest GC. Jeśli program "porzuci"
    > jakiś obiekt Item, to w pamięci wisi zarówno obiekt Item, jak i
    > odpowiadający jego id wpis w mapie. Wyciek.
    > Na szczęście są słabe referencje, ale uwaga - Item jest *wartością* a
    > nie kluczem w mapie. W najlepszym razie GC posprząta obiekty Item, ale
    > wpisy w mapie pozostaną, przez co mapa i tak puchnie w nieskończoność.
    > Wyciek.
    > Można pomyśleć o podpięciu się pod finalizator, ale w opinii
    > szanowanych obywateli jest to robienie wiochy. Zamiast tego doradzono
    > mi zrobić *dodatkowy wątek*, który będzie okresowo jeździł po mapie i
    > wywalał wpisy, których wartości się wyzerowały (czyli te wpisy,
    > których obiekty Item zostały posprzątane przez GC).
    > To rozwiązanie *prawie* działa, ale ma takie dwie przykre cechy:
    > * Komplikuje projekt wymuszając istnienie dodatkowego wątku.

    Prawda.

    > * Wprowadza dodatkowe wartości konfiguracyjne służące do strojenia
    > pracy tego wątku (okres skanowania).
    >

    Nie trzeba watku skanujacego - wystarczy usuwajacy. Od skanowania jest
    java.lang.ref.ReferenceQueue

    --
    Michal


  • 4. Data: 2009-07-27 09:50:54
    Temat: Re: Opowiadanie o GC
    Od: Krzysiek Kowaliczek <k...@g...com>

    Maciej Sobczak wrote:
    [ciach]
    > Piszę *prawie*, bo pomiędzy posprzątaniem obiektów Item (hint: to się
    > dzieje dopiero wtedy, gdy GC jest wystarczająco zestresowany, żeby się
    > w ogóle ruszyć - co następuje akurat wtedy, gdy *zaczyna brakować
    > pamięci*) a skanem mapy jest pewien odstęp czasu, kiedy niepotrzebne
    > już wpisy w mapie *nadal* zajmują pamięć, zmniejszając efektywnie pulę
    > dostępnej pamięci. To powoduje, że przy dalszej pracy programu GC
    > szybciej będzie zestresowany i znowu coś tam posprząta, ale przez nowe
    > wiszące wpisy w mapie i tak zostawi jeszcze mniejszą pulę wolnej
    > pamięci. Ostatecznie program wylatuje na jej braku, chociaż z
    > projektowego punktu widzenia może nigdy nie używać więcej, niż jednego
    > obiektu Item.
    > Oczywiście zmiany okresu skanowania mapy wpływają jedynie na
    > *prawdopodobieństwo* poprawnego działania całego programu i nigdy nie
    > można tej poprawności *zagwarantować*.
    >

    Dlaczego? Watek sprzątający może sam "kopnąć" GC.

    > Ot, taka sobie historyjka. Ale może ktoś znudzony upałami i burzami
    > wpadnie na jakiś pomysł, jak to poprawić.
    >
    > Jedną z możliwości jest dodatnie do klasy Item funkcji close() i
    > uprzejme poproszenie programisty, żeby jej używał. Jest to
    > rozwiązanie, którego poziom abstrakcji i wartość projektowa
    > odpowiadają językowi C.

    To nie jest złe. Dla bezpieczeństwa w finalizatorze można
    dodać asercje o niezwolnionym obiekcie.

    > Są inne?
    >

    Może zobaczyć jak zaimplementowali WeakHashMap ( tam "weak"
    jest klucz a nie wartość ).

    Pozdrawiam
    KK


  • 5. Data: 2009-07-27 10:09:38
    Temat: Re: Opowiadanie o GC
    Od: Michal Kleczek <k...@g...com>

    Michal Kleczek wrote:

    [ciach]
    >
    > Nie trzeba watku skanujacego - wystarczy usuwajacy. Od skanowania jest
    > java.lang.ref.ReferenceQueue
    >

    Sprobuj moze jakos tak:

    class IdMap<ID, ITEM> {

    private final Map<Reference<?>, ID> refToIdMap = new HashMap();
    private final Map<ID, Reference<ITEM>> idToRefMap = new HashMap();

    private final ReferenceQueue<ITEM> referenceQueue = new ReferenceQueue();

    //needs to be static so that we do not keep
    //reference to the parent IdMap
    private static class Remover<S, T> implements Runnable {

    //keep just a (weak) reference to parent map
    //so that we know when to finish removal
    private final Reference<IdMap<S, T>> idMapRef;

    private ReferenceQueue<T> getRefQueue() {
    IdMap<S, T> idMap = idMapRef.get();
    return idMap != null ? idMap.referenceQueue : null;
    }

    public Remover(IdMap<S, T> idMap) {
    this.idMapRef = new WeakReference<IdMap<S, T>>(idMap);
    }

    @Override
    public void run() {
    try {
    ReferenceQueue<T> referenceQueue = getRefQueue();
    while (referenceQueue != null) {
    //wait for next reference to remove
    final Reference<? extends T> itemRef = referenceQueue.remove();
    final IdMap<S, T> idMap = idMapRef.get();
    if (idMap != null) {
    idMap.remove(itemRef);
    }

    referenceQueue = getRefQueue();
    }
    }
    catch (InterruptedException e) {
    //ignore and return
    }
    }

    }

    private synchronized void remove(Reference<?> ref) {
    final ID id = refToIdMap.remove(ref);
    idToRefMap.remove(id);
    }

    public IdMap() {
    new Thread(new Remover(this)).start();
    }

    public ITEM get(ID id) {
    final Reference<ITEM> itemRef = idToRefMap.get(id);
    return itemRef != null ? itemRef.get() : null;
    }

    public synchronized void put(ID id, ITEM item) {
    final Reference<ITEM> itemRef = new WeakReference<ITEM>(item);
    idToRefMap.put(id, itemRef);
    refToIdMap.put(itemRef, id);
    }

    }


    --
    Michal


  • 6. Data: 2009-07-27 10:11:52
    Temat: Re: Opowiadanie o GC
    Od: Krzysiek Kowaliczek <k...@g...com>

    Michal Kleczek wrote:
    > Maciej Sobczak wrote:
    >
    > [ciach]
    >> W C++ typ Item ma destruktor, który wyrejestrowuje swoje id z mapy.
    >> Dzięki temu, jeśli program "porzuci" jakiś obiekt Item (przez co nie
    >> może już go obserwować i reagować na zmiany jego stanu), to
    >> odpowiadający mu wpis w mapie jest natychmiast wyrzucany.
    >
    > Moglbys pokazac kod w C++ ktory to robi bez uzycia jakichs smart pointerow
    > zliczajacych referencje? Bo ja nie bardzo to widze (ale specem nie
    > jestem) - chyba ze wszystkie obiekty Item o tym samym id sa rownowazne -
    > tyle ze wtedy nie jest potrzebna zadna mapa.
    >

    np.:
    struct Item
    {
    ~Item ()
    {
    mapa::releaseId ( id_ );
    }

    Item ()
    {
    id_ = mapa::getId ();
    }

    int id_;

    };

    for (...)
    {
    Item item;
    }

    >> W
    >> szczególności, jeśli program używa obiektów Item w takiej pętli:
    >>
    >> for (...)
    >> {
    >> Item it;
    >> // ...
    >> }
    >>
    >> to w efekcie mapa nigdy nie ma więcej, niż 1 wpis. Zużycie pamięci
    >> jest wtedy *stałe* (albo ma znaną górną granicę) - dotyczy to również
    >> bardziej złożonych, ale nadal cyklicznych układów.
    >
    > Nie widze w powyzszym przykladzie mapy ani pobierania obiektow Item z tejze.
    >

    j.w.

    Pozdrawiam
    KK


  • 7. Data: 2009-07-27 10:16:10
    Temat: Re: Opowiadanie o GC
    Od: Michal Kleczek <k...@g...com>

    Krzysiek Kowaliczek wrote:

    [ciach]
    >
    > Może zobaczyć jak zaimplementowali WeakHashMap ( tam "weak"
    > jest klucz a nie wartość ).
    >

    O ile pamietam z WeakHashMap jest taki problem (jezeli to jest problem), ze
    czyszczenie z obiektow WeakReference nastepuje dopiero w momencie uzycia
    mapy.

    --
    Michal


  • 8. Data: 2009-07-27 10:19:13
    Temat: Re: Opowiadanie o GC
    Od: Michal Kleczek <k...@g...com>

    Krzysiek Kowaliczek wrote:

    [ciach]
    >
    > np.:
    > struct Item
    > {
    > ~Item ()
    > {
    > mapa::releaseId ( id_ );
    > }
    >
    > Item ()
    > {
    > id_ = mapa::getId ();
    > }
    >
    > int id_;
    >
    > };
    >
    > for (...)
    > {
    > Item item;
    > }
    >

    Ja chyba potrzebuje jasniej :)
    Nadal nie widze tutaj pobierania obiektow Item z mapy.
    Co robi mapa::getId() ?

    Michal

    --
    Michal


  • 9. Data: 2009-07-27 10:21:31
    Temat: Re: Opowiadanie o GC
    Od: Michal Kleczek <k...@g...com>

    Michal Kleczek wrote:

    [ciach]
    > public synchronized void put(ID id, ITEM item) {
    > final Reference<ITEM> itemRef = new WeakReference<ITEM>(item);

    tu oczywiscie new WeakReference(item, referenceQueue);

    --
    Michal


  • 10. Data: 2009-07-27 10:24:49
    Temat: Re: Opowiadanie o GC
    Od: "Sebastian Nibisz" <e...@p...onet.pl>

    Ja zaproponuje takie rozwiązanie.

    1. Oprócz mapy kluczy, utworzyć kolejkę par [ID, Item].
    2. W konstruktorze obiektu Item
    a) pobrać N > 1 par z kolejki,
    b) usunąć z mapy wpisy z martwymi referencjami,
    c) pary z żywymi referencjami dodać na koniec kolejki,
    d) utworzyć parę [ID, Item] dla bieżącego obiektu i dodać ja do mapy,
    oraz na koniec kolejki.

    Dla przyjętej wartości N można wyliczyć, procentową zajętość
    niewykorzystanej pamięci, dla pesymistycznego przypadku.

    Pozdrawiam,
    - Bastek -

strony : [ 1 ] . 2 ... 8


Szukaj w grupach

Szukaj w grupach

Eksperci egospodarka.pl

1 1 1

Wpisz nazwę miasta, dla którego chcesz znaleźć jednostkę ZUS.

Wzory dokumentów

Bezpłatne wzory dokumentów i formularzy.
Wyszukaj i pobierz za darmo: