当前位置:网站首页>201215-03-19 - cocos2dx memory management - specific explanation "recommended collection"

201215-03-19 - cocos2dx memory management - specific explanation "recommended collection"

2022-07-07 21:05:00 Full stack programmer webmaster

Hello everyone , I meet you again , I'm the king of the whole stack .

because cocos2dx Our use c++ Written , So memory management is just a trap , If you don't understand memory but business logic , What else are you playing c++, I watched this thing for a long time today , In fact, it is understood in essence , But there is a barrier that cannot be crossed , Finally, it was done tonight , So I want to share with you . Strive for me to put the high-quality essence of the Internet through my own understanding . Share it with you .

There are generally two ways to manage memory , Reference counting and garbage collection .

We cocos2dx Reference counting is used , And very hot java It's garbage collection . Reference count , Specific explanation of garbage collection :

Reference count : By maintaining a reference counter for each object , Record the number of times the object is currently referenced .

When an object adds a reference , Add one counter : And lose a quote , Counter minus one ; When count is 0 when . Marks the end of the life cycle of the object . Actively trigger the recycling and release of objects .

Reference counting solves the problem of object lifecycle management , But the problems of heap fragmentation and cumbersome management still exist . Garbage collection : He introduced his own active memory payback period , Try to completely liberate the program ape from the complex memory management task . He will actively track all references of each object , In order to find the object in use , Then there are real estate enterprises and objects that are no longer needed . Garbage collection period is usually executed as a separate low-level thread , Clear and recycle objects that have died or have not been used for a long time in the memory heap under unpredictable circumstances .

Let's focus on reference counting , Its principle is that we reference an object , Just add one to the reference count of the object , If you lose a reference and an object, reduce the reference count by one . stay cocos2dx The way is retain and release, Let's see CCObject. stay CCObject There's a property in it m_uReference Is the reference count .

CCObject::CCObject(void)<span style="white-space:pre">	</span>
: m_nLuaID(0)
, m_uReference(1) // when the object is created, the reference count of it is 1 Note that there , Default this m_uReference yes 1 Of 
, m_uAutoReleaseCount(0)
{
    static unsigned int uObjectCount = 0;

    m_uID = ++uObjectCount;
}
void CCObject::retain(void)
{
    CCAssert(m_uReference > 0, "reference count should greater than 0");

    ++m_uReference;
}

retain Method , Each time will be m_uReference Add one

void CCObject::release(void)
{
    CCAssert(m_uReference > 0, "reference count should greater than 0");
    --m_uReference;

    if (m_uReference == 0)
    {
        delete this;
    }
}

release Each time will be m_uReference Minus one , And assume 0 Then delete fall .

Suppose we manage manually , Just use the above method .

But we mainly say that we actively manage , Taking the initiative to manage yourself is actually that you just work . We will hand over the issue of release to Cocos2dx Engine to release , There is no need for us to manually call release

Generally, there will be one in our class create Method . This method is probably like this

MyScene * MyScene::create()
{
	MyScene *pRet = new MyScene;
	if (pRet && pRet->init())
	{
		pRet->autorelease();<span style="white-space:pre">	</span>// Note that there , At this time, we give this object to the engine , We don't need to release manually again , Just wait for the engine to release itself 
		return pRet;
	}
	else
	{
		CC_SAFE_DELETE(pRet);
	}
	return NULL;
}

Some people will ask . You simply don't release because of such a sentence , It's up to the engine , How did you achieve . Is this thing reliable , Don't panic , Let's enter the method to see

CCObject* CCObject::autorelease(void)
{
    CCPoolManager::sharedPoolManager()->addObject(this);	// Let's go in again , See the following method 
    return this;
}

void CCPoolManager::addObject(CCObject* pObject)
{
    getCurReleasePool()->addObject(pObject);	// Let's go in again . See the following method 
}

void CCAutoreleasePool::addObject(CCObject* pObject)
{
    m_pManagedObjectArray->addObject(pObject);	// Here suppose we continue to go down , Then we will eventually find one pObject.retain The method of ,

    CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1");
    ++(pObject->m_uAutoReleaseCount);
    pObject->release(); // no ref count, in this case autorelease pool added.
}

First of all, we want to explain CCAutoreleasePool It is called self active release pool , stay CCPoolManager ( Actively release the pool management class by yourself ) We have a member variable in the class CCArray * m_pReleasePoolStack; This is to actively release the pool stack , Inside the store CCAutoreleasePool Example .

CCAutoreleasePool There's a CCArray * m_pManagedObjectArray, This is an internal array of objects .

In general, their relationship is like this . Every time we actively manage objects by ourselves , It will be added to the memory free pool , You might ask , We don't release this thing , When will it be released , The answer is to release every frame cycle . And create a self active release pool again .

Let's see mainLoop Code

void CCPoolManager::pop()
{
    if (! m_pCurReleasePool)
    {
        return;
    }

     int nCount = m_pReleasePoolStack->count();

    m_pCurReleasePool->clear();	// Look here, everyone . This means that the memory pool is empty , We should see how he empties 
 
      if(nCount > 1)
      {
        m_pReleasePoolStack->removeObjectAtIndex(nCount-1);

//         if(nCount > 1)
//         {
//             m_pCurReleasePool = m_pReleasePoolStack->objectAtIndex(nCount - 2);
//             return;
//         }
        m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2);// Here we initialize the memory pool again in a new frame 
    }

    /*m_pCurReleasePool = NULL;*/
}

void CCAutoreleasePool::clear()
{
    if(m_pManagedObjectArray->count() > 0)
    {
        //CCAutoreleasePool* pReleasePool;
#ifdef _DEBUG
        int nIndex = m_pManagedObjectArray->count() - 1;
#endif

        CCObject* pObj = NULL;
        CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj)
        {
            if(!pObj)
                break;

            --(pObj->m_uAutoReleaseCount);// This means that the sign of self active management becomes 0 了 
            //(*it)->release();
            //delete (*it);
#ifdef _DEBUG
            nIndex--;
#endif
        }

        m_pManagedObjectArray->removeAllObjects();
    }
}

It's probably like this , We imagine assuming that we are simply create A manager , I didn't hang it on the rendering tree , Our citation count must be 1 ah , And then through the reduction of their own active release pool . Will be released .

Case one :

CCScene *pscene = CCScene::create(); // The reference count is 1, Default internally autorelease 了

.

.

. After the frame cycle, the stack is cleared , Quote minus one ,pscene He was killed .

Another situation :

CCScene *pscene = CCScene::create(); // The reference count is 1. Default internally autorelease 了

addChild(pscene);// The reference count is 2.

.

.

.

After a frame cycle of stack clearing , Quote minus one . The reference count becomes 1. And next time, I won't actively release myself into the pool . So this spirit can always be on the rendering tree , When do we want to delete him . Maybe you want to release this “ spirit ”, We still need to call it manually release. Or call it autorelease Method .

Let me make a summary , Well, that's it , Let's have one CCObject It's running autorelease Method , The active release pool will be given to us by default at the beginning of the next frame cycle -1, Because we managed . Theoretically , Suppose the reference count is zero after subtracting one , It is what we should release , But we trust the engine , The engine will be duty bound to help us release it .

Suppose we not only created it ourselves , It is also added to the rendering tree . It means that we will continue to use this spirit , If you actively release the pool, you will reduce the reference count by one to one , The engine will know that you are creat You are still using this spirit , I don't care , Keep him alive , I still have to clean up my active release pool . Because I want to prepare for this frame cycle .

I unconsciously wrote this point . Originally, I still wanted to say a little more , Brush your teeth and go to bed early , Today, this really makes my day dark . The sun gave forth no more of its light , I understand . I just didn't convert my thoughts , At first, I didn't understand why I was so released , Later I learned . We should have done this . But sometimes these are registration functions , Interrupt function and so on , We don't know when to do , So let the engine do it , Because he knows how to do .

Brush one's teeth , sleep , Good night, everyone .......

.

.

Publisher : Full stack programmer stack length , Reprint please indicate the source :https://javaforall.cn/116441.html Link to the original text :https://javaforall.cn

原网站

版权声明
本文为[Full stack programmer webmaster]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207071843025682.html