Реализация файла отображения памяти std::allocator зависает на устройстве WM6

У меня есть проект Visual Studio 2008 C++ для Windows Mobile 6.x, где мне нужно больше памяти, чем доступно мне в слоте процесса 32 МБ. Итак, я рассматриваю использование файлов с отображением памяти. Я создал стандартную реализацию распределителя, которая заменяет new/delete на CreateFileMapping. и MapViewOfFile.

Предполагаемое использование примерно такое:

struct Foo
{
    char a[ 1024 ];
};

int _tmain( int argc, _TCHAR* argv[] )
{
    std::vector< boost::shared_ptr< Foo > > v;
    for( int i = 0; i < 40000; ++i )
    {
        v.push_back( boost::allocate_shared< Foo >( MappedFileAllocator< Foo >() ) );
    }
    return 0;
}

С std::allocator я могу получить 28197 итераций в этом примере, прежде чем я получу исключение std::bad_alloc. С MappedFileAllocator я получаю 32371 итерацию, прежде чем устройство полностью зависнет и его нужно будет перезагрузить. Поскольку у моего устройства 512 МБ ОЗУ, я ожидал, что смогу получить гораздо больше итераций из этого цикла.

Моя реализация MappedFileAllocator:

template< class T >
class MappedFileAllocator
{
public:
    typedef T         value_type;
    typedef size_t    size_type;
    typedef ptrdiff_t difference_type;
    typedef T*        pointer;
    typedef const T*  const_pointer;
    typedef T&        reference;
    typedef const T&  const_reference;

    pointer address( reference r ) const { return &r; };
    const_pointer address( const_reference r ) const { return &r; };

    /// convert a MappedFileAllocator<T> to a MappedFileAllocator<U>
    template< class U >
    struct rebind { typedef MappedFileAllocator< U > other; };

    MappedFileAllocator() throw() : mapped_file_( INVALID_HANDLE_VALUE ) { };

    template< class U >
    explicit MappedFileAllocator( const MappedFileAllocator< U >& other ) throw()
        : mapped_file_( INVALID_HANDLE_VALUE )
    {
        if( other.mapped_file_ != this->mapped_file_ )
        {
            ::DuplicateHandle( GetCurrentProcess(), 
                other.mapped_file_,
                GetCurrentProcess(),
                &this->mapped_file_,
                0,
                FALSE,
                DUPLICATE_SAME_ACCESS );
        }
    };

    pointer allocate( size_type n, const void* /*hint*/ = 0 )
    {
        if( n > max_size() )
           throw std::bad_alloc();

        if( n > 0 )
        {
            size_type buf_size = n * sizeof( value_type );
            mapped_file_ = ::CreateFileMapping( INVALID_HANDLE_VALUE, 
                NULL,
                PAGE_READWRITE,
                0,
                buf_size,
                L"{45E4FA7B-7B1E-4939-8CBB-811276B5D4DE}" );

            if( NULL == mapped_file_ )
                throw std::bad_alloc();

            LPVOID f = ::MapViewOfFile( mapped_file_, 
                FILE_MAP_READ | FILE_MAP_WRITE, 
                0, 
                0, 
                buf_size );

            if( NULL == f )
            {
                ::CloseHandle( mapped_file_ );
                mapped_file_ = INVALID_HANDLE_VALUE;
                throw std::bad_alloc();
            }
            return reinterpret_cast< T* >( f );
        }

        return 0;
    };

    void deallocate( pointer p, size_type n )
    {
        if( NULL != p )
        {
            ::FlushViewOfFile( p, n * sizeof( T ) );
            ::UnmapViewOfFile( p );
        }
        if( INVALID_HANDLE_VALUE != mapped_file_ )
        {
            ::CloseHandle( mapped_file_ );
            mapped_file_ = INVALID_HANDLE_VALUE;
        }
    };

    size_type max_size() const throw() 
    { 
        return std::numeric_limits< size_type >::max() / sizeof( T );
    };

    /// handle to the memory-mapped file
    HANDLE mapped_file_;

private:

    /// disallow assignment
    void operator=( const MappedFileAllocator& );

}; // class MappedFileAllocator

Кто-нибудь может подсказать, где я ошибаюсь в реализации MappedFileAllocator?

Спасибо, PaulH


person PaulH    schedule 04.05.2011    source источник
comment
проверить, выровнен ли каждый указатель, возвращаемый функцией allocate(), по какой-либо границе; похоже, что MapViewOfFile может потреблять одну страницу каждый раз, когда вы пытаетесь сопоставить файл.   -  person vividos    schedule 28.06.2011
comment
@vividos - они выровнены ARM по 4-байтовым границам. WM-версия MVOF не требует выравнивания страницы. msdn.microsoft.com/en-us/library/aa914405.aspx   -  person PaulH    schedule 29.06.2011
comment
Тогда я не знаю, в чем проблема. Следующее, что я бы попробовал, это пул памяти в LMA, выделенный VirtualAlloc(), вместо использования анонимного сопоставления файлов. Этот документ может помочь: davidfindlay.org/weblog/files/ce_lma.php   -  person vividos    schedule 30.06.2011
comment
@vividos - Это красиво. Я собираюсь попробовать. Спасибо!   -  person PaulH    schedule 30.06.2011


Ответы (3)


Проверьте, поддерживает ли boost::interprocess Windows Mobile. У них есть средства для создания файлов с отображением памяти и использования памяти для размещения любой части данных, которую вы хотите:

http://www.boost.org/doc/libs/1_47_0/doc/html/interprocess/sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file

person DR.    schedule 26.07.2011

Вы используете анонимное сопоставление файлов (без фактического файла). При этом сопоставление поддерживается системным файлом подкачки. Вполне вероятно, что в мобильной ОС на самом деле нет файла подкачки, потому что «жесткий диск», вероятно, является флэш-устройством. Как правило, пейджинг виртуальной памяти на флэш-устройства — плохая идея, потому что природа виртуальной памяти подразумевает большой объем операций записи, которые могут быстро сжечь флэш-память (особенно старые типы).

Кажется, это подтверждается количеством итераций, которые вы получаете. Похоже, вы можете отобразить до 60% всей памяти на вашем устройстве.

Возможно, вы сможете заставить это работать с большими разделами, если откроете настоящий файл (используя OpenFile) и сопоставите его вместо использования INVALID_FILE_HANDLE в CreateFileMapping. Но будьте осторожны с вашей флэш-памятью (и производительностью!), если вы собираетесь очень много писать в сопоставление файлов.

person SoapBox    schedule 04.05.2011
comment
Большая область памяти Windows Mobile составляет почти 1 ГБ. В лучшем случае я мог потреблять только 31 МБ до сбоя. 31 МБ — это далеко не 60% от общего объема на устройстве, даже если все, что у меня было, — это 512 МБ — msdn.microsoft.com/en-us/library/bb331824.aspx - person PaulH; 05.05.2011
comment
Переключившись на реализацию с поддержкой файлов, я смог выделить 26283 раза (25 МБ), прежде чем устройство зависло. Я могу опубликовать эту реализацию, если это необходимо. - person PaulH; 05.05.2011
comment
Эээ, простите, ошибся на порядок, думал 310 Мб. В любом случае, если вы не можете получить более 31 МБ из своего 32-мегабайтного слота для процесса, то, возможно, ответ таков: вот почему они называют его 32-мегабайтным слотом для процесса? - person SoapBox; 05.05.2011
comment
Вот почему я перешел к MappedFileAllocator, он должен выделять память в LMA, которая находится за пределами 32-мегабайтного слота процесса. Я могу убедиться, что память слота процесса не заполняется, тогда как это происходит с std::allocator. - person PaulH; 05.05.2011

Я только что получил значок «Популярный вопрос» для этого, поэтому я решил (с опозданием) опубликовать ответ. У меня заканчивались доступные ручки. В ядре Windows Mobile имеется короткий счетчик без знака, относящийся к выделению дескрипторов, которое было переполнено. Как только это произошло, устройство зависло.

person PaulH    schedule 09.04.2014