3 votes

Faire en sorte que les allocations importantes soient automatiquement engagées dès la première touche

Comment puis-je allouer de la mémoire dans Windows sans qu'elle ne soit engagée avant la première touche ?

Je vois que VirtualAlloc me permet de réserver une plage de mémoire, mais je dois ensuite engager manuellement des sections de cette mémoire avant de l'utiliser. J'aimerais que l'enregistrement soit automatique lorsque je la référence pour la première fois.

De plus, si possible, je ne veux pas que la mémoire soit remise à zéro avant d'être enregistrée.

(En passant, cela peut être fait sous Linux en configurant un mappage de mémoire privée d'un morceau de /dev/zero).

1voto

Mordachai Points 3234

Vous pouvez utiliser un pointeur intelligent de votre propre conception qui le commet lors de la première déréférence (en surchargeant bien sûr les opérateurs de déréférence et d'indirection).

Il s'agit d'un exemple de pointeur intelligent qui crée une instance d'un objet donné lors de la première déréférence (instanciation paresseuse). Même idée, en gros :

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
};

1voto

On peut supposer que l'objectif est de différer l'attribution de la garantie pour les adresses, plutôt que de s'engager spécifiquement lors de la première utilisation. Si c'est le cas, il semble que Windows le fera automatiquement pour vous !

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

Devis pertinent :

Comme alternative à la méthode dynamique dynamique, le processus peut simplement engager la région entière au lieu de seulement la réserver. Les deux méthodes entraînent la même utilisation de la mémoire physique car les pages engagées ne consomment pas de pas de mémoire physique tant qu'elles ne sont pas qu'elles soient accédées pour la première fois.

En ce qui concerne la remise à zéro des nouvelles pages, je pense qu'il s'agit d'une fonction de sécurité et qu'elle ne peut être évitée. (Le système a un fil spécial qui remet à zéro les pages lorsqu'il y a un temps mort, donc avec un peu de chance il y aura toujours une page remise à zéro immédiatement prête à être utilisée en cas de besoin).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X