使大量分配在第一次接触时自动提交

发布于 2024-10-10 11:39:54 字数 207 浏览 0 评论 0原文

如何在 Windows 中分配内存,但在第一次触摸之前才提交内存?

我看到 VirtualAlloc 允许我保留一定范围的内存,但随后我需要在使用前手动提交该内存的部分。我希望当我第一次引用它时自动提交。

另外,如果可能的话,我不希望在提交之前将内存清零。

(顺便说一句,这可以在 Linux 上通过设置 /dev/zero 块的私有内存映射来完成)

How can I allocate memory in Windows but not have it committed until first touch?

I see that VirtualAlloc lets me reserve a range of memory, but I then need to manually commit sections of that memory before use. I'd like the committing to be automatic when I first reference it.

Also, if possible, I do not want the memory zeroed before being committed.

(As an aside, this can be done on Linux by setting up a private memory mapping of a chunk of /dev/zero)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

路还长,别太狂 2024-10-17 11:39:54

您可以使用自己设计的智能指针,该指针在第一次取消引用时提交它(当然通过重载取消引用和间接运算符)。

这是一个示例智能指针,它在第一次取消引用(延迟实例化)时创建给定对象的实例。同样的想法,基本上:

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

You can use a smart-pointer of your own design which commits it upon first dereference (by of course overloading the dereference & indirection operators).

This is an example smart pointer which creates an instance of a given object upon first dereference (lazy instantiation). Same idea, basically:

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
};
-黛色若梦 2024-10-17 11:39:54

据推测,延迟分配地址支持是目标,而不是在第一次使用时专门承诺?如果是这样,Windows 似乎会自动为您执行此操作!

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

相关引用:

作为动态的替代方案
分配,过程可以简单地
提交整个区域而不是
只保留它。两种方法的结果
在相同的物理内存使用情况下
因为提交的页面不会消耗
任何物理存储,直到它们被
首次访问。

至于新页面被重置为零,我相信这是一个安全功能,无法避免。 (系统有一个特殊的线程,可以在出现死区时间时将页面归零,因此如果幸运的话,总会有一个归零的页面立即可供在必要时使用。)

Presumably the deferred allocation of backing for the addresses is the goal, rather than necessarily specifically committing on first use? If so, it looks as if Windows will do that for you automatically!

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

Relevant-looking quotation:

As an alternative to dynamic
allocation, the process can simply
commit the entire region instead of
only reserving it. Both methods result
in the same physical memory usage
because committed pages do not consume
any physical storage until they are
first accessed.

As for new pages being reset to zero, I believe this is a security feature and can't be avoided. (The system has a special thread that zeros pages when there is some dead time, so with any luck there will always be a zeroed page immediately ready for use when necessary.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文