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

#c #memory #windows-mobile #virtual-memory #memory-mapped-files

#c #память #windows-mobile #виртуальная память #файлы с отображением памяти

Вопрос:

У меня есть проект 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 Tamp;        reference;
    typedef const Tamp;  const_reference;

    pointer address( reference r ) const { return amp;r; };
    const_pointer address( const_reference r ) const { return amp;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 >amp; other ) throw()
        : mapped_file_( INVALID_HANDLE_VALUE )
    {
        if( other.mapped_file_ != this->mapped_file_ )
        {
            ::DuplicateHandle( GetCurrentProcess(), 
                other.mapped_file_,
                GetCurrentProcess(),
                amp;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 MappedFileAllocatoramp; );

}; // class MappedFileAllocator
  

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

Спасибо, PaulH

Комментарии:

1. проверьте, выровнен ли каждый указатель, возвращаемый из allocate(), по некоторой границе; похоже, что MapViewOfFile может занимать одну страницу каждый раз, когда вы пытаетесь сопоставить файл.

2. @vividos — Они выровнены по ARM в пределах 4 байт. WM-версия MVOF не требует выравнивания страницы. msdn.microsoft.com/en-us/library/aa914405.aspx

3. Тогда я не знаю, в чем проблема. Следующее, что я бы попробовал, это пул памяти в LMA, выделенный VirtualAlloc (), вместо использования анонимного сопоставления файлов. Этот документ может помочь: davidfindlay.org/weblog/files/ce_lma.php

4. @vividos — Это прекрасно. Я собираюсь попробовать это. Спасибо!

Ответ №1:

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

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

Ответ №2:

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

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

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

Комментарии:

1. Объем памяти Windows Mobile составляет почти 1 ГБ. В лучшем случае я мог использовать только 31 МБ до сбоя. 31 МБ — это не более 60% от общего объема на устройстве, даже если все, что у меня было, это 512 МБ — msdn.microsoft.com/en-us/library/bb331824.aspx

2. Переключившись на реализацию с файловой поддержкой, я смог выделить 26283 раза (25 МБ), прежде чем устройство зависло. Я могу опубликовать эту реализацию, если необходимо.

3. Извините, я был сбит на порядок, я думал, что это 310 МБ. В любом случае, если вы не можете извлечь более 31 МБ из своего слота процесса 32 МБ, то, возможно, ответ таков … вот почему они называют это слотом процесса 32 МБ?

4. Вот почему я перешел к MappedFileAllocator он должен выделять память в LMA, которая находится за пределами слота процесса 32 МБ. Я могу убедиться, что память слота процесса не заполняется, тогда как это происходит с std::allocator .

Ответ №3:

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