我有一个适用于Windows Mobile 6.x的Visual Studio 2008 C ++项目,我需要的内存比32MB进程插槽中的内存要多。所以,我正在寻找使用内存映射文件。我创建了一个标准的分配器实现,用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
,在得到std::bad_alloc
异常之前,我可以在该示例中获得28197次迭代。使用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
实施可能出错吗?
谢谢, PaulH
答案 0 :(得分:1)
检查boost :: interprocess是否支持Windows Mobile。它们具有创建内存映射文件和使用内存分配所需数据的功能:
答案 1 :(得分:0)
您正在使用匿名文件映射(没有实际文件支持的映射)。执行此操作时,映射由系统页面文件支持。移动操作系统可能实际上没有页面文件,因为“硬盘”可能是闪存设备。对闪存设备进行虚拟内存分页通常是一个坏主意,因为虚拟内存的性质意味着大量写入会迅速烧毁闪存(特别是旧类型)。
这似乎得到了你获得的迭代次数的支持。看起来您可以映射到设备总内存的大约60%。
如果您打开一个真实文件(使用OpenFile
)并映射而不是使用INVALID_FILE_HANDLE
中的CreateFileMapping
,则可以使用更大的部分。但是如果你要写入你的文件映射,请小心你的闪存(和性能!)。
答案 2 :(得分:0)
我刚刚获得了这个“流行问题”的徽章,所以我想(姗姗来迟)发布了答案。我的可用手柄用完了。 Windows Mobile内核中有一个未签名的短计数器,它与溢出的句柄分配有关。一旦发生这种情况,设备就会冻结。