2013-04-11 18 views

cevap

18

İlk olarak, Boost Havuzu kütüphanesinde arkasındaki temel fikir bilmelidir: enter image description here

: simple_segregated_storage, sabit boyutlu parçalar bir bellek bloğu bölümlemek için bir tek başına bağlantılı listeye benzer ve sorumludur

Bir bellek havuzu, boş bellek parçaları listesini tutar. Bu yüzden bloklardan ve parçalardan bahsetmiştik: bellek havuzu, bir bellek bloğu ayırmak ve aynı boyutta birçok bellek parçasına bölerek new veya malloc kullanır.
Adresin bir sonraki öbek adresini saklamak için 8, 4 bayt ile hizalandığını farz edin, böylece bir bellek bloğu (8 bayt * 32 parça) aşağıdaki gibidir (bellek adresi yalnızca soruyu göstermek içindir, gerçek bir değil) :
Şimdi a memory block

, kullanıcı iki kez 8 bayt bellek ayırır herhalde, bu yüzden parçalar: [0xDD00,0xDD08), [0xDD08,0xDD10) kullanılmaktadır. Bir süre sonra, kullanıcı [0xDD00,0xDD08] 'de belleği serbest bırakır, bu nedenle bu yığın ücretsiz listeye geri döner. Şimdi blok şu şekildedir: buna işaret etmek Sonrasında kullanıcı,) [0xDD08,0xDD10 de listede geri bu öbek yerleştirmenin en basit yolu belleği serbest bırakır

enter image description here

first yenilenmesini sağlar, sabit zamanlı karmaşıklık. simple_segregated_storage<T>::free() bu tam yapıyor: Bundan sonra

void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunk) 
{ //! Free a chunk. 
    //! \pre chunk was previously returned from a malloc() referring to the same free list. 
    //! \post !empty() 
    BOOST_POOL_VALIDATE_INTERNALS 
    nextof(chunk) = first; 
    first = chunk; 
    BOOST_POOL_VALIDATE_INTERNALS 
} 

, liste böyle olacaktır:
unordered list
Şimdi bu operasyonlardan sonra kendi adresi ile sipariş edilmez parçalar listesini fark! Sırasını verirken siparişi korumak istiyorsak, belleği uygun sırayla listeye yerleştirmek için pool<>::free() yerine pool<>::ordered_free() numaralı telefonu arayın. bellek listesinde hiç boş öbek olduğunda Gördüğümüz gibi

void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION() 
{ 
    if (!store().empty()) 
    return (store().malloc)(); 
    return malloc_need_resize(); 
} 

void * ordered_malloc() 
{ 
    if (!store().empty()) 
    return (store().malloc)(); 
    return ordered_malloc_need_resize(); 
} 

, sadece farklı: Şimdi hafıza havuzunda sırası ne tanıyorum, en boost::pool<>::malloc ve boost::pool<>::ordered_malloc kaynak koduna kazmak izin blokları. Bu senaryoda, yeni bir bellek bloğu ayırır, serbest listesini havuzun ücretsiz listesine birleştirir, bu iki yöntem arasındaki fark, ücretsiz listeleri birleştirirken boost::pool<>::ordered_malloc sırasını korur.
Yukarıdaki soru için: 1.
Peki, neden sipariş önemlidir ?! Bellek havuzu, sıralanmamış parçalar ile mükemmel çalışır gibi görünüyor!
İlk olarak, bitişik bir n dizisi bulmak istiyorsak, sıralanan ücretsiz liste daha kolay hale getirecektir.

class X { … }; 

    void func() 
    { 
     boost::object_pool<X> alloc; 

     X* obj1 = alloc.construct(); 
     X* obj2 = alloc.construct(); 
     alloc.destroy(obj2); 
    } 

: İkinci, en boost::pool türetilmiş sınıfın bir göz atalım: Ayrıca, örneğin elle nesneyi yok ederken boost::object_pool, bu object_pool nesnenin imha olmayan ayırmanın nesneleri otomatik olarak imha sağlar Yukarıdaki kod tamam, bellek sızıntısı veya çift silme yok! Bu sihri boost::object_pool nasıl yapar? en boost::object_pool yıkıcı ilgili (benim makinede boost 1.48 var) uygulanmasını bulalım:

template <typename T, typename UserAllocator> 
object_pool<T, UserAllocator>::~object_pool() 
{ 
#ifndef BOOST_POOL_VALGRIND 
    // handle trivial case of invalid list. 
    if (!this->list.valid()) 
    return; 

    details::PODptr<size_type> iter = this->list; 
    details::PODptr<size_type> next = iter; 

    // Start 'freed_iter' at beginning of free list 
    void * freed_iter = this->first; 

    const size_type partition_size = this->alloc_size(); 

    do 
    { 
    // increment next 
    next = next.next(); 

    // delete all contained objects that aren't freed. 

    // Iterate 'i' through all chunks in the memory block. 
    for (char * i = iter.begin(); i != iter.end(); i += partition_size) 
    { 
     // If this chunk is free, 
     if (i == freed_iter) 
     { 
     // Increment freed_iter to point to next in free list. 
     freed_iter = nextof(freed_iter); 

     // Continue searching chunks in the memory block. 
     continue; 
     } 

     // This chunk is not free (allocated), so call its destructor, 
     static_cast<T *>(static_cast<void *>(i))->~T(); 
     // and continue searching chunks in the memory block. 
    } 

    // free storage. 
    (UserAllocator::free)(iter.begin()); 

    // increment iter. 
    iter = next; 
    } while (iter.valid()); 

    // Make the block list empty so that the inherited destructor doesn't try to 
    // free it again. 
    this->list.invalidate(); 
#else 
    // destruct all used elements: 
    for(std::set<void*>::iterator pos = this->used_list.begin(); pos != this->used_list.end(); ++pos) 
    { 
     static_cast<T*>(*pos)->~T(); 
    } 
    // base class will actually free the memory... 
#endif 
} 

bellek bloklarının listesinde (list, boost::pool<> veri üyesi tüm parçalar geçer, yerini saklar ve sistemden tahsis edilen tüm bellek bloklarının boyutları), içinde herhangi bir parçanın serbest listede de gösterilip gösterilmediğini bulmak, eğer değilse, nesnenin yıkıcısını çağırır, sonra hafızayı boşaltır. Yani, std::set_intersection()'un yaptığı gibi, iki kümenin kesişme noktası oluyor! Liste sıralanırsa, bunu yapmak çok daha hızlı olacaktır. Aslında boost::object_pool<> yılında, düzen, kamu üye işlevlerini gereklidir: boost::object_pool<>::malloc() ve boost::object_pool<>::free() sadece boost::pool<>::ordered_malloc() ve boost::pool<>::ordered_free() sırasıyla çağrı:

element_type * malloc BOOST_PREVENT_MACRO_SUBSTITUTION() 
{ //! Allocates memory that can hold one object of type ElementType. 
    //! 
    //! If out of memory, returns 0. 
    //! 
    //! Amortized O(1). 
    return static_cast<element_type *>(store().ordered_malloc()); 
} 
void free BOOST_PREVENT_MACRO_SUBSTITUTION(element_type * const chunk) 
{ //! De-Allocates memory that holds a chunk of type ElementType. 
    //! 
    //! Note that p may not be 0.\n 
    //! 
    //! Note that the destructor for p is not called. O(N). 
    store().ordered_free(chunk); 
} 

Yani queston 2 için: Çoğu durumlarda boost::pool<>::ordered_malloc kullanmayın gerekir.

+2

Mükemmel cevap! –

İlgili konular