使用内存映射文件来提高你程序的性能

简介:

本人在学习《WINDOWS核心编程》的时候对JEFFREY大师提到的一个小程序写了两个版本来比较性能,该程序的原始需求是这样的:对一个大文件进行倒序,也就是将一个文件头变成尾,尾变成头。

  使用的方法有很多种,这里使用两个方法来比较,主要是突出使用内存映射文件好处;两种方法为:内存映射文件方法,I/O读写的缓存办法。

  第一种办法是创建内存映射文件对象,然后将该对象映射到进程的地址空间中,再读取文件内容,然后倒序,再写入文件。

  第二中方法是,将文件内容读入一个大的缓冲区,然后倒序,再写入文件,中间对原来的文件删除,然后重新写入。

  程序编写如下

  第一种方法, 内存映射文件方式
None.gifBOOL FileReverse(PCTSTR pszPathName)
ExpandedBlockStart.gif {
InBlock.gifHANDLE hFile = CreateFile(pszPathName,GENERIC_WRITE|GENERIC_READ,0,NULL
InBlock.gif,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
InBlock.gifif(hFile == INVALID_HANDLE_VALUE)
ExpandedSubBlockStart.gif{
InBlock.gifprintf("File could not be opened.");
InBlock.gifreturn FALSE;
ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gifDWORD dwFileSize = GetFileSize(hFile,NULL);
InBlock.gif
InBlock.gifHANDLE hFileMap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,
InBlock.gifdwFileSize+sizeof(char),NULL);
InBlock.gif
ExpandedSubBlockStart.gifif(hFileMap == NULL){
InBlock.gifCloseHandle(hFile);
InBlock.gifreturn FALSE;
ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gifPVOID pvFile = MapViewOfFile(hFileMap,FILE_MAP_WRITE,0,0,0);
InBlock.gif
ExpandedSubBlockStart.gifif(pvFile == NULL){
InBlock.gifCloseHandle(hFileMap);
InBlock.gifCloseHandle(hFile);
InBlock.gifreturn FALSE;
ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gifPSTR pchAnsi = (PSTR)pvFile;
InBlock.gifpchAnsi[dwFileSize/sizeof(char)]=0;
InBlock.gif_strrev(pchAnsi);
InBlock.gif
InBlock.gifpchAnsi = strchr(pchAnsi,'\n');
ExpandedSubBlockStart.gifwhile(pchAnsi != NULL){
InBlock.gif*pchAnsi++ ='\r';
InBlock.gif*pchAnsi++ ='\n';
InBlock.gifpchAnsi = strchr(pchAnsi,'\n');
ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gifUnmapViewOfFile(pvFile);
InBlock.gifCloseHandle(hFileMap);
InBlock.gif
InBlock.gifSetFilePointer(hFile,dwFileSize,NULL,FILE_BEGIN);
InBlock.gifSetEndOfFile(hFile);//实际上不需要写入了。
InBlock.gif
CloseHandle(hFile);
InBlock.gif
InBlock.gifreturn TRUE;
ExpandedBlockEnd.gif}

None.gif

第二中方法, 使用缓存的方式
None.gifBOOL FileReverseNoMap(PCTSTR pszPathName)
ExpandedBlockStart.gif {
InBlock.gifHANDLE hFile = CreateFile(pszPathName,GENERIC_WRITE|GENERIC_READ,0,NULL
InBlock.gif,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
InBlock.gifif(hFile == INVALID_HANDLE_VALUE)
ExpandedSubBlockStart.gif{
InBlock.gifprintf("File could not be opened.");
InBlock.gifreturn FALSE;
ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gifDWORD dwFileSize = GetFileSize(hFile,NULL);
InBlock.gif//CloseHandle(hFile);
InBlock.gif
char *readBuf = new char[dwFileSize+1];
InBlock.gifDWORD nRead = 0,nRet =0;
ExpandedSubBlockStart.gifwhile(nRead<dwFileSize){
InBlock.gifif(ReadFile(hFile,readBuf+nRead,dwFileSize-nRead,&nRet,NULL) ==TRUE)
ExpandedSubBlockStart.gif{
InBlock.gifnRead+= nRet;
ExpandedSubBlockEnd.gif}

InBlock.gifelse
ExpandedSubBlockStart.gif{
InBlock.gifprintf("Can read the file!");
InBlock.gifCloseHandle(hFile);
ExpandedSubBlockEnd.gif}

ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gifPSTR pchAnsi = (PSTR)readBuf;
InBlock.gifpchAnsi[dwFileSize/sizeof(char)]=0;
InBlock.gif_strrev(pchAnsi);
InBlock.gif
InBlock.gifpchAnsi = strchr(pchAnsi,'\n');
ExpandedSubBlockStart.gifwhile(pchAnsi != NULL){
InBlock.gif*pchAnsi++ ='\r';
InBlock.gif*pchAnsi++ ='\n';
InBlock.gifpchAnsi = strchr(pchAnsi,'\n');
ExpandedSubBlockEnd.gif}

InBlock.gifCloseHandle(hFile);
InBlock.gifDeleteFile(pszPathName);
InBlock.gif
InBlock.gifHANDLE hWriteFile = CreateFile(pszPathName,GENERIC_WRITE|GENERIC_READ,0,NULL
InBlock.gif,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
InBlock.gifWriteFile(hWriteFile,readBuf,dwFileSize,&nRet,NULL);
InBlock.gifCloseHandle(hWriteFile);
InBlock.gif
InBlock.gifdelete readBuf;
InBlock.gif
InBlock.gifreturn TRUE;
ExpandedBlockEnd.gif}

 我运行了几次,比较结果如下:
文件大小(byte) 1方法时间(ms) 2方法时间(ms)
25416 0 0
101664 0 0
406656 0 10
1219968 10 30
3202416 21 100
9607248 80 551
67250736 581 5568

  本人测试机器的CPU是迅池1.5的笔记本,内存为712MB

  通过上面的测试我们可以看到使用内存映射文件的好处,在文件内存越大这种优势就体现的越明显,其中主要的原因是:

  内存映射文件直接将文件的地址映射到进程的地址空间中,那么操作文件就相当于在内存中操作一样,省去了读和写I/O的时间;第二种方式是必须这么做(READFILE,WRITEFILE),这个过程是很慢的。 
目录
相关文章
|
7天前
|
C语言 Android开发 C++
基于MTuner软件进行qt的mingw编译程序的内存泄漏检测
本文介绍了使用MTuner软件进行Qt MinGW编译程序的内存泄漏检测的方法,提供了MTuner的下载链接和测试代码示例,并通过将Debug程序拖入MTuner来定位内存泄漏问题。
基于MTuner软件进行qt的mingw编译程序的内存泄漏检测
|
22天前
|
缓存 Java 测试技术
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
使用JMeter对项目各个接口进行压力测试,并对前端进行动静分离优化,优化三级分类查询接口的性能
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
|
15天前
|
存储 缓存 Linux
用户态内存映射
【9月更文挑战第20天】内存映射不仅包括物理与虚拟内存间的映射,还涉及将文件内容映射至虚拟内存,使得访问内存即可获取文件数据。mmap 系统调用支持将文件或匿名内存映射到进程的虚拟内存空间,通过多级页表机制实现高效地址转换,并利用 TLB 加速映射过程。TLB 作为页表缓存,存储频繁访问的页表项,显著提升了地址转换速度。
|
14天前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
|
5天前
|
存储 安全 Linux
将文件映射到内存,像数组一样访问
将文件映射到内存,像数组一样访问
12 0
|
28天前
|
存储 运维
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
|
21天前
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
43 0
|
2月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
|
3月前
|
存储 分布式计算 Hadoop
HadoopCPU、内存、存储限制
【7月更文挑战第13天】
215 14
|
2月前
|
存储 监控 Docker
如何限制docker使用的cpu,内存,存储
如何限制docker使用的cpu,内存,存储

热门文章

最新文章

相关实验场景

更多
下一篇
无影云桌面