9

我有一个适用于 Windows Mobile 6.x 的 Visual Studio 2008 C++ 项目,我需要比 32MB 进程槽中可用的内存更多的内存。所以,我正在考虑使用内存映射文件。我创建了一个标准分配器实现,用CreateFileMappingMapViewOfFile替换 new/delete 。

预期用途是这样的:

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 次迭代。由于我的设备有 512MB 的 RAM,我希望能够从该循环中获得更多的迭代。

我的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实施可能出错的地方吗?

谢谢,保罗

4

3 回答 3

1

检查 boost::interprocess 是否支持 Windows Mobile。它们具有创建内存映射文件和使用内存分配您想要的任何数据的功能:

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

于 2011-07-26T18:10:25.547 回答
0

您正在使用匿名文件映射(一个没有实际文件支持它的文件)。执行此操作时,映射由系统页面文件支持。移动操作系统很可能实际上没有页面文件,因为“硬盘”可能是闪存设备。对闪存设备进行虚拟内存分页通常不是一个好主意,因为虚拟内存的性质意味着大量写入会迅速烧毁闪存(尤其是旧类型)。

这似乎得到了您获得的迭代次数的支持。看起来您最多可以映射设备上大约 60% 的总内存。

OpenFile如果您打开一个真实文件(使用)并映射它而不是使用INVALID_FILE_HANDLEin ,您可能可以让它与更大的部分一起使用CreateFileMapping。但是,如果您要大量写入文件映射,请注意您的闪存(和性能!)。

于 2011-05-04T23:30:22.343 回答
0

我刚刚得到了这个问题的“热门问题”徽章,所以我想我会(迟来的)发布答案。我的可用手柄用完了。Windows Mobile 内核中有一个与溢出的句柄分配相关的无符号短计数器。一旦发生这种情况,设备就会冻结。

于 2014-04-09T13:45:40.223 回答