Although today's wireless handsets have far more memory than just a few short years ago, memory remains one of those things where more is simply better. A frequent pattern in application development is to load something into main memory, manipulate it (such as parse or display) it in some way, and then dispose of the memory you used in the first place. Not only is this a hassle, but it can fragment the heap, leading to the inability to allocate large blocks later on. Fortunately, in some cases there's a better way—simply map the desired file to memory using Qualcomm Brew's IFILE_Map API.
Before I show you how to do this, I should tell you the limitations of this API (as of this writing, anyway). First, the interface was introduced in BREW 3.1, so it doesn't exist on older handsets. Secondly, the file must be read-only, and you can read only from the memory mapped region, not write to the region to update the file. Finally, it only works for certain kinds of files: specifically, constant files placed on the handset by the OEM. These restrictions mean that the API is best-suited for developers of embedded Brew applications, such as device manufacturers and their partners.
The actual process to use IFILE_Map is quite simple:
Areas of your application where mapping files to memory may help include:
One other area of dubious applicability I should mention is media: The Brew IMedia interface can read from both memory and files on the file system, so there's little need to map a media file on the file system to a memory region and invoke the IMedia interfaces using the resulting mapped region.
Before I show you how to do this, I should tell you the limitations of this API (as of this writing, anyway). First, the interface was introduced in BREW 3.1, so it doesn't exist on older handsets. Secondly, the file must be read-only, and you can read only from the memory mapped region, not write to the region to update the file. Finally, it only works for certain kinds of files: specifically, constant files placed on the handset by the OEM. These restrictions mean that the API is best-suited for developers of embedded Brew applications, such as device manufacturers and their partners.
Mapping a File to Memory with IFILE_Map
When you map a file to memory using IFILE_Map, you're creating a pointer in memory that can be used to read the contents of the file as if it were loaded on the heap. The idea is the same as with the BSD mmap and munmap functions, but given the limitations of the BREW platform, it's understandably less flexible.The actual process to use IFILE_Map is quite simple:
- Create your desired data file and embed it in the handset's production environment as a constant (read-only) file.
- In your application, open the file using an instance of IFILEMGR_OpenFile, passing the _OFM_READ flag to indicate read-only access to the file.
- Determine the part (perhaps all) of the file you'd like to map into a memory region, obtaining the size of the file as a guideline using IFILE_GetInfo.
- Invoke IFILE_Map to obtain a pointer to the file's contents.
- Read from the pointer in the normal way (say, pass it to a parser to parse what's needed from the file).
- When you're done, close the file using IFILE_Release.
{Opening the file with IFILEMGR is straightforward; so is mapping the file, once you know the arguments. IFILE_Map returns a pointer to the mapped region in memory, given:
IFileMgr *pifm;
ISHELL_CreateInstance( pMe->m_pIShell, AEECLSID_FILEMGR,
(void **)&pifm );
if ( pifm )
{
IFile *pif = IFILEMGR_OpenFile(
pifm, THE_FILE_NAME, _OFM_READ );
if ( pif )
{
FileInfo fi = { 0 };
int err;
char *p;
IFILE_GetInfo( pif, &fi );
p = IFILE_Map( pif,
NULL,
fi.dwSize,
AEE_FMAP_PROT_READ,
AEE_FMAP_SHARED,
0 );
if ( p )
{
// Do stuff with the contents.
Parse( pMe, p );
}
else
{
// Handle the error
}
IFILE_Release( pif );
}
IFILEMGR_Release( pifm );
}
}
- A pointer to an open file.
- The starting point in memory at which to map the file, which should be NULL.
- The number of bytes to map from the file starting at the current seek position for the file.
- How the file should be mapped (read-only, writable, or executable). At present, only AEE_FMAP_PROT_READ is supported.
- Indicates how shared memory should be handled. The region can be shared between callers using the AEE_FMAP_SHARED flag.
- The offset from the start of the file.
Why Memory Map Files?
There are two reasons to map files into memory. I've already hinted at the first: Mapping files into memory can reduce the amount of memory your application consumes, and potentially reduce heap fragmentation as well. It can also lead to clearer code, by eliminating the need to write record-handling and record-parsing code that reads and parses chunks of your data file. Although the first reason may be less important in today's world of handsets with multiple megabytes of heap, the second reason remains important no matter how much memory the device has.Areas of your application where mapping files to memory may help include:
- Dynamic user interfaces, in which the look and feel of your application (including widget placement) is specified indirectly through configuration files at run-time.
- Parsing of large files in XML or other formats (potentially for the aforementioned purpose), eliminating the need to construct a parser that can handle tags split across read buffer boundaries.
- Managing read-only data in non-serialized forms (in other words, direct memory dumps) from disk files.
One other area of dubious applicability I should mention is media: The Brew IMedia interface can read from both memory and files on the file system, so there's little need to map a media file on the file system to a memory region and invoke the IMedia interfaces using the resulting mapped region.
0 nhận xét:
Đăng nhận xét