最近经常有些同事问起内存方面的东西,感觉有很多人(尤其是一些新手)对内存的使用存在一定的认识不足,比如说windows 2k下,2个模块,模块1个new出的内存为什么可能在模块2中释放失败.综其原因是对各种层面内存的概念不清晰或者没有,所以总结下:
c/c++语言分配的内存 比如说malloc,new等
CRT 对管理程序
OS的虚拟内存管理
这三层是由上至下的一个顺序调用
其中中间那个比较重要,我们平时c/c++程序里调用的malloc/new等其实是它提供的接口,它负责对用户层的内存需求做一些管理,当需要内存的时候他会向下层的OS虚拟内存块请求内存,比如说用户可能malloc(1)10次,而CRT会在第一次malloc(1)的时候向OS要一页(Page)(如果内存不够的话),然后后面的9次malloc(1)都会从刚才要过来的那页去割分,而不需要频繁向OS去申请,所以CRT的这部分作用就是做一个中介管理层吧
回到刚才那个问题“windows 2k下模块1个new出的内存为什么可能在模块2中释放失败",在windows 2k下同一个dll在不同的模块里有不同的copy,对于mscrt.dll这个dll,在模块1中有1份,模块2中有另一份,在1中分配的被1中的mscrt.dll管理程序所知道,如果这个指针拿到模块2中的mscrt.dll来释放,它根本没有分配过这块内存的记录,当然会失败。
理解这些东西的另一个用处就是可以充分地意识到不同层次的内存管理有不同的理由,所以必须高效的选择使用,拿游戏程序来说,游戏程序一般涉及到大量的资源和很多的游戏逻辑对象。显然这两种不同的需求性质不同。对于逻辑游戏对象,一般是数量多,单个快小,适合用crt去分配(需要的话自己上层再做些用户层内存管理)。而后者一般涉及很大的文件,量不多,但每个都很大,这样子的就不适合用crt.dll来分配了,应该越过这层crt的管理,直接用OS提供的以page为单位的虚拟内存来管理比较高效
既然谈到虚拟内存,就再说下虚拟内存的几个方面使用:
1)页对齐。 应用程序请求页面时候要做到页面对齐。换句话说不要让小于页面的一段数据放到2个页面上去,这样会要寻址2次,同时让OS一些快速加载方法无用武之处
2)预加载。 OS交换页面文件是一页一页来的,换句话说你加载一个页里面的任何一个字节,系统会把整个页加载,可以利用这点自己做预加载。例如:
for(size_t i = 0 ; i < 10;i++) // 10 page
{
#pragma optimize(off)
BYTE byte = page[i][0]; // access the first byte,so load the whole page
#pragma optimize(on)
}