2011-01-04 3 views
3

Как я могу выделить память в Windows, но не использовать ее до первого касания?Сделать большие ассигнования автоматически фиксированными при первом касании

Я вижу, что VirtualAlloc позволяет мне резервировать диапазон памяти, но мне тогда необходимо вручную зафиксировать разделы этой памяти перед использованием. Я бы хотел, чтобы это было автоматически, когда я впервые обратился к нему.

Кроме того, если возможно, я не хочу, чтобы память была обнулена перед тем, как была зафиксирована.

(Кстати, это может быть сделано на Linux, установив личное отображение памяти куска/разработчика/ноль)

ответ

1

Вы можете использовать смарт-указатель вашего собственного дизайна, который обязует его на первое разыменование (конечно, перегрузка разыменования & операторов косвенности).

Это пример умного указателя, который создает экземпляр данного объекта при первом разыменовании (ленивом экземпляре). Та же самая идея, в основном:

template <typename T> 
struct default_constructor_factory 
{ 
    T * operator()() { return new T; } 
}; 

template <typename T, typename F = default_constructor_factory<T> > 
class lazy_ptr : boost::noncopyable 
{ 
public: 
    typedef T element_type; 
    typedef T value_type; 
    typedef F factory_type; 
    typedef lazy_ptr<T,F> this_type; 

    lazy_ptr() : m_ptr(), m_factory() { } 
    lazy_ptr(F factory) : m_ptr(), m_factory(factory) { } 
    ~lazy_ptr() { if (m_ptr != NULL) delete m_ptr; } 

    T & operator*() const 
    { 
     return *get(); 
    } 

    T * operator->() const 
    { 
     return get(); 
    } 

    T * get() const 
    { 
     if (m_ptr == NULL) 
      m_ptr = m_factory(); 
     return m_ptr; 
    } 

    void reset(T * p) 
    { 
     if (p != m_ptr) 
     { 
      if (m_ptr != NULL) 
       delete m_ptr; 
      m_ptr = p; 
     } 
    } 

    T * release() 
    { 
     T * p = m_ptr; 
     m_ptr = NULL; 
     return p; 
    } 

    // non-dereferencing accessors 

    T * peek() const 
    { 
     // may return NULL 
     return m_ptr; 
    } 

    bool dereferenced() const 
    { 
     return peek() != NULL; 
    } 

// operator bool() const { return dereferenced(); } 

    // handle intrinsic conversion to testable bool using unspecified_bool technique 
    typedef T * this_type::*unspecified_bool_type; 
    operator unspecified_bool_type() const // never throws 
    { 
     return dereferenced() ? &this_type::m_ptr : NULL; 
    } 

private: 
    // we must remain it's only owner! 
    mutable T * m_ptr; 

    // our factory generates the needed element on-demand 
    mutable factory_type m_factory; 
}; 

// shared_lazy_ptr 
// 
// we act as a copyable lazy pointer 
// essentially, we add reference counting to a single shared lazy pointer 
// 
template <typename T, typename F = default_constructor_factory<T> > 
class shared_lazy_ptr 
{ 
public: 
    typedef T element_type; 
    typedef T value_type; 
    typedef F factory_type; 
    typedef lazy_ptr<T,F> ptr_type; 
    typedef shared_lazy_ptr<T,F> this_type; 

    shared_lazy_ptr() : m_ptr(new ptr_type) { } 
    shared_lazy_ptr(F factory) : m_ptr(new ptr_type(factory)) { } 

    // copy ctor 
    shared_lazy_ptr(const this_type & rhs) : m_ptr(rhs.m_ptr), m_references(rhs.m_references) { } 

    // assignment 
    this_type & operator = (const this_type & rhs) 
    { 
     if (m_references.Reattach(rhs.m_references)) 
      delete m_ptr; 
     m_ptr = rhs.m_ptr; 
     return *this; 
    } 

    ~shared_lazy_ptr() 
    { 
     if (m_references.IsOnly()) 
      delete m_ptr; 
    } 

    T & operator*() const 
    { 
     return *get(); 
    } 

    T * operator->() const 
    { 
     return get(); 
    } 

    T * get() const 
    { 
     return m_ptr->get(); 
    } 

    void reset(T * p) 
    { 
     if (p != get()) 
     { 
      if (m_ptr != NULL) 
       delete m_ptr; 
      m_ptr = p; 
     } 
    } 

    // non-dereferencing accessors 

    T * peek() const 
    { 
     // may return NULL 
     return get()->peek(); 
    } 

    bool dereferenced() const 
    { 
     return peek() != NULL; 
    } 

// operator bool() const { return dereferenced(); } 

    // handle intrinsic conversion to testable bool using unspecified_bool technique 
    typedef T * this_type::*unspecified_bool_type; 
    operator unspecified_bool_type() const // never throws 
    { 
     return dereferenced() ? &this_type::m_ptr : NULL; 
    } 

private: 
    lazy_ptr<T, F> * m_ptr;   // shared *lazy* pointer to the actual object 
    ReferenceCount m_references; // shared reference count to our lazy pointer 
}; 
1

Предположительно отложенное выделение поддержки для адресов является целью, а не обязательно конкретно совершения при первом использовании? Если это так, похоже, Windows автоматически сделает это за вас!

http://msdn.microsoft.com/en-us/library/aa366803(v=vs.85).aspx

Соответствующий вид цитата:

В качестве альтернативы динамического распределения , процесс может просто совершить весь регион, а не только зарезервировать его. Оба метода приводят к в том же физическом объеме использования памяти , поскольку зафиксированные страницы не потребляют любое физическое хранилище до тех пор, пока они не достигнут .

Что касается новых страниц, сбрасываемых до нуля, я считаю, что это функция безопасности, и ее нельзя избежать. (Система имеет специальный поток, который имеет нулевые страницы, когда есть какое-то мертвое время, поэтому при любой удаче всегда будет нулевая страница, готовая к использованию, когда это необходимо.)

+0

Проблема в том, что это позволит мне сделать для которых достаточно свободной виртуальной памяти. Я хотел бы сделать гигантские распределения (величины больше, чем RAM + swap). Понятно, что это произойдет в какой-то момент в будущем, если я коснусь слишком большого количества страниц, но я не против этого. – pauldoo

+0

Документы предполагают, что VirtualAlloc будет делать именно то, что вы хотите, я думаю? Файл страницы будет расти по мере необходимости, если позволит дисковое пространство, поэтому это не является жестким пределом. Что касается свободной виртуальной памяти, вы связаны тем, что все, что вы делаете, потому что это предел в адресном пространстве. (Вы можете добавить еще несколько бит в 32-битный режим, используя PAE - Windows поддерживает это, но я никогда не использовал его.) –

+1

Я не хочу ограничиваться дисковым пространством (например, ram + swap). Я хочу чтобы сделать поистине гигантские распределения на 64-битной основе, и только зафиксировали страницы и увеличили пространство подкачки, когда я касаюсь их. – pauldoo