成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用對象池加速游戲內存分配

開發 前端
游戲開發中經常需要頻繁產生、銷毀大量對象,內存本身夠不夠用是一方面,尤其是在手機等內存本來就有限的設備上面,另外一點是分配的速度不會對游戲體驗造成影響,也就是不能影響幀率。

游戲開發中經常需要頻繁產生、銷毀大量對象,內存本身夠不夠用是一方面,尤其是在手機等內存本來就有限的設備上面,另外一點是分配的速度不會對游戲體驗造成影響,也就是不能影響幀率。

相比內存池,對象池更易用更容易管理,而且還可以利用臟數據,也就是上次被回收掉的對象的數據。而且偶爾的空間分配失敗其實不是那么重要(后面會講怎么在會失敗的情況下完成分配任務),游戲中還是速度更重要些。

原理

一次申請大量連續內存(整數個對象大小),最好用堆,當然如果用棧數組也沒人攔你,棧空間可是相當有限…

由于分配的對象生存期是不固定的(如下圖),池不可能保持已分配對象的連續性,這時進行塊移動會降低程序效率。

  分配       分配 分配   分配  

所以需要把閑置對象的指針放入容器中來管理。此容器必須能快速存取刪,而且不需要頻繁大距離移動容器元素指針,最好是剛從容器中釋放的元素能馬上讓 下一個元素使用,這時候棧就是一個很好的選擇了。初始時將所有閑置對象指針壓入棧,分配時pop,棧為空時返回空;釋放時將對象指針push進棧即可。

實現

其實boost已經提供了對象池了,那為什么還要自己實現一個呢?當然是要方便DIY了…其實你也可以用boost的對象池來第二次封裝

這部分直接參看附件源碼吧

使用

這才是真正的重點

分配時直接用Sobot* p = ObjPool<Sobot>::alloc()?不,還應該使用placement new調用其構造函數:

new(p) Sobot()

你想在你的代碼中充斥大量這樣的代碼嗎?放到工廠里面也許是一種辦法,但是工廠引用到了對象池了。而大師告訴我們好的設計要保持職責單一,用與不用對象池應該不影響原系統的正常運行。而且還有一點,用這種辦法,就只能和某些組件絕緣了,比如智能指針。

此時重載new與delete就至關重要了:

  1. static void* operator new(size_t) { 
  2.  
  3.     return SobotPool::instance().alloc(); 
  4.  
  5.  
  6. static void operator delete(void* p) { 
  7.  
  8.     SobotPool::instance().free(reinterpret_cast<Sobot*>(p)); 
  9.  

一個對象中往往充斥著大量指針,而這些指針指向的空間往往大于包含他們的對象本身。如果將這些指針所在在類也應用對象池,一方面是池的容量你無法估 計,另一方面是使用起來麻煩。而且你也無法向上面這樣給每個類注入new與delete的重載。用代理?呵呵,項目中估計會出一堆問題。這時候我們不妨使 用臟數據,也就是說對象池中保存的對象全是可以直接使用的對象,而并非空對象,對象中的成員指針變量引用到的內存不在池中。為了保證安全,清空這些內存在 池銷毀時進行。

和上面的功能一起,我們可以定義一個宏,免得每次使用都得重復大量代碼。如下:

  1. #define USING_DIRTY_DATA true 
  2.  
  3. // 如果不是方便測試需要,可以將這行 
  4.  
  5. // typedef ObjPool<obj_class, max_size> obj_class##Pool; \ 
  6.  
  7. // 標注為private 
  8.  
  9. #define DECLARE_USING_OBJ_POOL(obj_class, max_size, _using_dirty_data) \ 
  10.  
  11.     public: \ 
  12.  
  13.         typedef ObjPool<obj_class, max_size> obj_class##Pool; \ 
  14.  
  15.         friend class obj_class##Pool; \ 
  16.  
  17.         static const bool using_dirty_data = _using_dirty_data; \ 
  18.  
  19.     public: \ 
  20.  
  21.     ~obj_class() { \ 
  22.  
  23.         if (!_using_dirty_data) {this->purge();} \ 
  24.  
  25.     } \ 
  26.  
  27.     static void* operator new(size_t) { \ 
  28.  
  29.         return obj_class##Pool::instance().alloc(); \ 
  30.  
  31.     } \ 
  32.  
  33.     static void operator delete(void* p) { \ 
  34.  
  35.         obj_class##Pool::instance().free(reinterpret_cast<obj_class*>(p)); \ 
  36.  
  37.     } \ 
  38.  
  39.     static bool loadCache() { \ 
  40.  
  41.         while (true) { \ 
  42.  
  43.             obj_class* obj = new obj_class; \ 
  44.  
  45.             if (obj != NULL) { \ 
  46.  
  47.                 if (!obj->init()) { \ 
  48.  
  49.                     return false; \ 
  50.  
  51.                 } \ 
  52.  
  53.             } else { \ 
  54.  
  55.                 break; \ 
  56.  
  57.             } \ 
  58.  
  59.         }; \ 
  60.  
  61.         obj_class##Pool::instance().freeAll(); \ 
  62.  
  63.         return true; \ 
  64.  
  65.     } 

調用時在類中加入如下代碼:

  1. // DECLARE_USING_OBJ_POOL(Bullet, BULLET_POOL_VOLUM, (NOT USING_DIRTY_DATA)) 
  2.  
  3. DECLARE_USING_OBJ_POOL(Bullet, BULLET_POOL_VOLUM, USING_DIRTY_DATA) 

LoadCache是游戲加載階段調用的,這里將進行所有池對象的初始化。為此,你還需要實現init和purge函數,分別是初始資源,銷毀資源 的,這些其實都只會被調用一次的。像狀態的初始化,大可放構造函數中,每次使用對象構造函數都會被調用的。外界是不能直接操作pool的。

如果池容量過小,分配失敗其實并不可怕。

見例子:

  1. // 大規模測試 
  2.  
  3.  list<Entity*> timer; 
  4.  
  5.  struct _Timer{ 
  6.  
  7.      list<Entity*>& _timer; 
  8.  
  9.      _Timer(list<Entity*>& timer) : _timer(timer) {} 
  10.  
  11.      void operator()() { 
  12.  
  13.          for (list<Entity*>::iterator iter = _timer.begin(); 
  14.  
  15.              iter != _timer.end();) { 
  16.  
  17.              Entity* entity = *iter; 
  18.  
  19.              if (entity->isValid()) { 
  20.  
  21.                  (*iter)->update(); 
  22.  
  23.              } else { 
  24.  
  25.                  entity->destroy(); 
  26.  
  27.                  iter = _timer.erase(iter); 
  28.  
  29.                  continue
  30.  
  31.              } 
  32.  
  33.              ++iter; 
  34.  
  35.          } // end for 
  36.  
  37.      } 
  38.  
  39.  } update_timer(timer); 
  40.  
  41.  const int num = 50
  42.  
  43.  log << endl << "大規模測試:" << endl; 
  44.  
  45.  for (int i = 0; i < num; ++i) { 
  46.  
  47.      Entity* entity = ObjManager<Entity>::instance().make("Bullet"); 
  48.  
  49.      if (IS_VALID_POINTER(entity)) { 
  50.  
  51.          log << "  alloced index:" << i << endl; 
  52.  
  53.          timer.push_back(entity); 
  54.  
  55.      } else { 
  56.  
  57.          log << "  alloc bullet failed, waiting..." << endl; 
  58.  
  59.          // 失敗了就多嘗試一次,反正任務量是20個 
  60.  
  61.          --i; 
  62.  
  63.      } 
  64.  
  65.      update_timer(); 
  66.  
  67.  } 
  68.  
  69.  // 不管使用什么模式都要自己回收所有的對象, 
  70.  
  71.  // 不要依賴于池析構時的對象釋放 
  72.  
  73.  for (list<Entity*>::iterator iter = timer.begin(); 
  74.  
  75.      iter != timer.end(); ++iter) { 
  76.  
  77.      (*iter)->destroy(); 

池容量為3,這是運行結果:

[0sec] 加載緩存
[0sec] Bullet1 with HP:2
[0sec] init Bullet1
[0sec] Bullet2 with HP:3
[0sec] init Bullet2
[0sec] Bullet3 with HP:5
[0sec] init Bullet3
[0sec]
大規模測試:
[0sec] Bullet10 with HP:5
[0sec]   alloced index:0
[0sec] Bullet11 with HP:1
[0sec]   alloced index:1
[0sec] Bullet12 with HP:1
[0sec]   alloced index:2
[0sec] destroy entity11
[0sec] Bullet13 with HP:2
[0sec]   alloced index:3
[0sec] destroy entity12
[0sec] Bullet14 with HP:3
[0sec]   alloced index:4
[0sec]   alloc bullet failed, waiting...
[0sec] destroy entity10
[0sec] destroy entity13
[0sec] Bullet15 with HP:2
(這里省略很多行…)
[1sec]   alloced index:46
[1sec] Bullet57 with HP:4
[1sec]   alloced index:47
[1sec]   alloc bullet failed, waiting...
[1sec] destroy entity55
[1sec] Bullet58 with HP:2
[1sec]   alloced index:48
[1sec]   alloc bullet failed, waiting...
[1sec]   alloc bullet failed, waiting...
[1sec] destroy entity56
[1sec] destroy entity57
[1sec] destroy entity58
[1sec] Bullet59 with HP:5
[1sec]   alloced index:49
[1sec] destroy entity59
[1sec]
釋放池
[1sec] purge Bullet59
[1sec] freeing sprite buf. size:3
[1sec] purge Bullet56
[1sec] freeing sprite buf. size:2
[1sec] purge Bullet57
[1sec] freeing sprite buf. size:1
請按任意鍵繼續. . .

附件下載

 

責任編輯:陳四芳 來源: cguage.com
相關推薦

2018-02-08 14:57:22

對象內存分配

2015-11-16 11:22:05

Java對象內存分配

2018-04-08 08:45:53

對象內存策略

2021-03-22 11:51:22

Java內存棧上

2020-06-04 12:15:37

Go內存池對象池

2021-07-30 07:22:51

JVM虛擬機棧 Stack

2021-11-29 05:32:47

內存規避安全工具惡意軟件

2021-07-14 10:00:32

Python內存測量

2010-09-25 14:12:50

Java內存分配

2021-02-28 13:22:54

Java內存代碼

2022-03-16 08:39:19

StackHeap內存

2023-03-26 00:43:42

JVM對象測試

2013-10-12 13:01:51

Linux運維內存管理

2011-07-15 01:10:13

C++內存分配

2022-01-13 10:30:21

C語言內存動態

2021-12-16 06:52:33

C語言內存分配

2010-09-25 15:40:52

配置JVM內存

2010-09-17 16:14:22

Java內存分配

2021-04-23 07:27:31

內存分配CPU

2022-03-07 10:54:34

內存Linux
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 在线免费小视频 | 国产精品国产精品国产专区不蜜 | 成人av免费| 国产一级特黄aaa大片评分 | 一区影院 | 日韩免费三级 | 黄视频在线网站 | 男女午夜激情视频 | 五月综合激情网 | 亚洲在线电影 | 91久久精品 | 亚洲狠狠爱 | 台湾佬成人网 | 91欧美激情一区二区三区成人 | 国产一级在线观看 | 日韩三级在线 | 欧美日韩久久久久 | 毛片一区二区 | 久久久久网站 | 国产激情在线播放 | 国产精品99久久久久久人 | 欧美成人精品一区 | 国产精品久久久久久久久久不蜜臀 | 久久亚洲国产 | 91av在线免费 | 国产天天操 | 国产一区二区三区视频 | 99re热精品视频 | 手机看片在线播放 | 97精品超碰一区二区三区 | 亚洲黄色在线免费观看 | 九九亚洲精品 | 亚洲乱码一区二区 | 欧产日产国产精品v | 黄色国产在线播放 | 亚洲成网 | 黄色毛片免费视频 | a级免费观看视频 | 欧美综合一区二区 | www国产精 | 久久久91精品国产一区二区三区 |