【忙到没空写博客的程度】表格型配置文件内存优化之一:简单内存分配器
来源:互联网 发布:小米营销知乎 编辑:程序博客网 时间:2024/05/16 09:20
最近是生平第一次全时间投入coding,甚至连写博客的精力都没了。这种感觉不是很好,希望能早日调节过来。努力工作之余深入思考我觉得很重要。
说正题,目前国产大型游戏开发里,经常用到Excel配置文件,这是一种文本文件,用Excel编辑表格后存为txt格式即可。除一些特殊情况外可以认为是用和换行分割的csv文件。这种配置文件的分析和读取不算难写,只要试验清楚Excel对待引号、换行等特殊符号的方式即可搞定。
这种配置文件有一个特点:空白单元格非常多,在超大型项目中大量重复的字符串会让人觉得很不爽。所以把此文件保存在内存里的时候有相当的优化的余地。精力有限,我直接记录我的结论了:
优化大体来说分两部分:
首先,分析加载表格时的内存分配优化。可以想象:大型游戏里,表格、行、单元格非常多,读取表格到内存时的分配的次数也是多如牛毛。好处是,这些配置文件一旦读取到内存里就没有必要销毁,因为游戏过程中可能随时会用到。所以这里用一个不能单独释放部分内存的简易内存分配器是合适的——也就是反复申请内存,最后一次全部释放。
其次,字符串共享。表格里有大量的重复短字符串,如果能够用带引用计数的字符串库,那么应该会有可观的内存优化空间(实际上已经被某个项目所证明了)。STL的引用计数方式不是很彻底,只是一定程度上的优化而已。而且今天刚刚发现,VS2010的STL库去掉了引用计数功能,原因我听说可能是多线程时的BUG。
(刚刚突然想到,如果是空白字符串,占用内存才一个字节,这时候采用共享意义会大打折扣(反而会增加到1个int?)。倒是对于5~30字节的字符串来说优化还是很有意义的。)
这篇博客里先记录一下我刚刚做的内存分配器。接口很简单,如下:
struct ROHeap;typedef struct ROHeap ROHeap;#ifdef __cplusplus // 这个是给VS编译器看的,如果某cpp文件包含此头文件,会加上extern "c",以防止C++函数名修饰extern "C" {#endifint ROHeapInit(ROHeap** heap, int page_size);void* ROHeapAlloc(ROHeap* heap, int byte_size);void ROHeapDeallocAll(ROHeap** heap);#ifdef __cplusplus}#endif
实现:ROHeap.c
#include "ROHeap.h"#include <malloc.h>#include <assert.h>typedef struct Page{struct Page* next;char* p;} Page;#define SIZE_PAGE_HEAD ((int)(sizeof(Page)))struct ROHeap{Page* head;Page* cur_page;int page_size;};int ROHeapInit(ROHeap** heap, int page_size){ROHeap* h;assert( page_size==0 || page_size>SIZE_PAGE_HEAD );if ( page_size == 0 ){page_size = 4096;}else{page_size = page_size;}*heap = (ROHeap*)malloc( sizeof(ROHeap) );h = *heap;h->page_size = page_size;h->cur_page = (Page*)malloc( page_size );h->cur_page->next = 0;h->cur_page->p = (char*)h->cur_page + SIZE_PAGE_HEAD;h->head = h->cur_page;return 0;}void* ROHeapAlloc(ROHeap* heap, int byte_size){void* ret;assert( byte_size>0 && byte_size <= heap->page_size - SIZE_PAGE_HEAD );assert( heap->cur_page != 0 );if ( byte_size > heap->page_size - (heap->cur_page->p - (char*)heap->cur_page) ){heap->cur_page->next = (Page*)malloc( heap->page_size );heap->cur_page = heap->cur_page->next;heap->cur_page->next = 0;heap->cur_page->p = (char*)heap->cur_page + SIZE_PAGE_HEAD;}ret = heap->cur_page->p;heap->cur_page->p += byte_size;return ret;}void ROHeapDeallocAll(ROHeap** heap){Page* page;Page* next;assert(heap);page = (*heap)->head;do{next = page->next;free( page );page = next;}while ( page != 0 );free( *heap );*heap = 0;}
简单说明:
1、实现时我用了纯C语言,编写过程中struct用着很不顺手(typedef struct的写法试了很多次)。另外要注意C语言的局部变量声明一定要在函数一开始,放在函数中间会报很诡异的错误: error C2143: 语法错误 : 缺少“;”(在“类型”的前面)
2、VS2010会根据文件扩展名是c还是cpp来确定编译行为,cpp调用c语言的接口时,要注意声明extern "C",而且要利用宏进行保护,保证编译到C文件和CPP文件时能够兼容(见上例)。其底层原理和C++函数名修饰有关,具体见相关书籍。
3、VS自带的内存泄漏检查工具使用方法:首先按顺序写上以下三个宏:
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
然后在需要检测的地方,调用这个函数: _CrtDumpMemoryLeaks();
在Debug模式下试验很好用,Release版本不会重载malloc所以无效。写内存分配器的时候必须拿这个好好测试一下:)
- 【忙到没空写博客的程度】表格型配置文件内存优化之一:简单内存分配器
- 简单的自定义内存分配器
- TrafficServer内存分配器优化
- TrafficServer内存分配器优化
- TrafficServer内存分配器优化
- 简单内存分配器
- 内存管理之一:STL中的内存分配器
- 内存管理之一:STL中的内存分配器
- 内存管理之一:STL中的内存分配器
- 内存管理之一:STL中的内存分配器
- 看csapp写内存分配器
- STL的内存分配器
- 快速的内存分配器
- STL的内存分配器
- STL的内存分配器
- STL的内存分配器
- STL的内存分配器
- STL的内存分配器
- MFC单文档添加控件和消息响应函数
- [RTSP][2012-06-16] RTSP PAUSE
- 判断多Frame网页是否真正加载完毕(CHtmlView)
- YUV图像
- 舍弃浮躁, 50条重要的C++学习建议(转载)
- 【忙到没空写博客的程度】表格型配置文件内存优化之一:简单内存分配器
- Linux server iostat分析
- 嵌入式linux,老手给新手的建议(转载)
- cocos2d-x Tests讲解三:Particle System(粒子系统)
- [RTSP][2012-06-16] RTSP TEARDOWN
- Android Activity 全屏
- 大型ORACLE数据库优化设计方案
- 子串计算
- js学习笔记(一)