本人刚学cocos2d-x就被内存管理问题卡住进展不下去了,出现奇怪的问题,不知道原因,问题描述如下:
/悲伤的分割线********/
我想在游戏一启动的时候就把所有的存储数据读入到内存中,包括用户数据和国际化的文本,以提高执行效率,所以我创建了一个GlobalizedDataManager类用于存储和管理这些数据。其中数据成员中有一个CCDictionary* p_labalDictionary;他里面的每个元素又是一个CCDictionary*,这样我可以通过key索引到不同的CCDictionary元素,这个key就是通过CCDictionary::createWithContentsOfFile方法读取的plist文件的文件名,而CCDictionary元素就是读取的plist文件,类定义如下,问题主要出现在红色的代码:
class GlobalizedDataManager
{
public:
enum LANGUAGE
{
EN, CN
};
private:
//the dictionary to contain labels
CCDictionary* p_labalDictionary;
// the pointer of db
sqlite3 p_DB;
// the error message
char p_errMsg;
// the sql string
string s_sqlstr;
// the returned value of sqlite3_exec
int i_result;
static GlobalizedDataManager* sp_manager;
private:
GlobalizedDataManager(void);
void initialDB();
void createTablesIfNotExist();
void loadGlobalizedLabels();
public:
static void initial();
static CCDictionary* getLabelDictionary(string);
static LANGUAGE getLanguage();
static void setLanguage(LANGUAGE);
~GlobalizedDataManager(void);
};
在实现里面,我在构造函数中调用
this->p_labalDictionary = CCDictionary::create();
this->p_labalDictionary->retain();创建这个字典,然后在loadGlobalizedLabels()里面填充了元素:
void GlobalizedDataManager::loadGlobalizedLabels()
{
string labels] = {
“menu_items.xml”,
“dialog_label.xml”
};
string labelPath = CCFileUtils::sharedFileUtils()->getWriteablePath() + “datalabel”;
string cnMenuItems = labelPath + “CN” + labels;
string enMenuItems = labelPath + “EN” + labels;
string cnDialogLabel = labelPath + “CN” + labels;
string enDialogLabel = labelPath + “EN” + labels;
CCDictionary* menu = NULL;
switch(getLanguage())
{
case CN:
menu = (CCDictionary*)CCDictionary::createWithContentsOfFile(cnMenuItems.c_str());
menu->retain();
this->p_labalDictionary->setObject(menu, labels.c_str());
this->p_labalDictionary->setObject(CCDictionary::createWithContentsOfFile(cnDialogLabel.c_str()), labels.c_str());
CCLog(“show: %d”, this->p_labalDictionary->count());
break;
default:
break;
}
}
如上所示,这个函数会在游戏启动的时候调用,将数据读入到static GlobalizedDataManager* sp_manager的实例中一直保存,然后我在其他类中调用
CCDictionary* GlobalizedDataManager::getLabelDictionary(string key)
{
CCDictionary* temp = (CCDictionary*)sp_manager->p_labalDictionary->objectForKey(key);
// if(temp->isSingleReference())
// temp->retain();
return temp;
}来获取读取的每个plist文件,现在问题就出现了,首先大家肯定会奇怪我上面已经retain()了放入的元素,为什么这里还要判断呢?因为我调试的时候发现:
(1)在menu->retain();执行完成之后menu中的m_uReference=2,m_uAutoReleaseCount=1,这个没有异议对吧。
(2)在this->p_labalDictionary->setObject(menu, labels.c_str());执行完成之后menu中的m_uReference=3,m_uAutoReleaseCount=1.
(3)在第一个调用getLabelDictionary(string)后menu中的m_uReference=2,m_uAutoReleaseCount=0按理说到了这一步menu就已经脱离了autoRelease()的管理了对吧,但是我执行getLabelDictionary(string)第二次时(第二次时是把CCscene重新加载一遍,但是因为labalDictionary是在静态的sp_manager里面存着的,所以我觉得应该是没有关系的),menu中的m_uReference=1,m_uAutoReleaseCount=0,再执行第3遍时menu中的m_uReference=随机数,m_uAutoReleaseCount=随机数,意思就是说这个menu被释放了!!这样我的程序试图读取menu中的数据就崩了,所以我必须再使用
// if(temp->isSingleReference())
// temp->retain();
这两行代码来判断一下,如果m_uReference=1了我再给他+1,我觉得很诡异啊,m_uAutoReleaseCount=0了按道理说引擎就不会再管理了啊,这到底是怎么回事呢?!求大神指点迷津!
