# 5.6 對象池
對象池服務可以減少從頭創建每個對象的系統開銷。在需要對象時從池中提取,在使用完對象時,把它放回池中,等待下一個請求。對象池使你能夠控制所使用的對象數量。在PHP的長駐進程模式下,對象池尤其重要,由于PHP的GC缺陷,在高并發下,PHP常駐進程內直接通過new創建對象,會導致PHP進程占用大量的內存,而且很容易出現OOM(out of memory)。
## 主要特性
- 創建固定數量的對象;
- 需要時從池中提取,不需要時歸還池中;
- 自動歸還對象;
- 根據有效期和使用次數淘汰對象
## 獲取對象池
```
$this->getContext()->getObjectPool()
```
理論上基于MSF框架的任何代碼都可以通過請求上下文對象來獲取對象池對象
## 獲取對象
如獲取Http Client對象:
```
$client = $this->getContext()->getObjectPool()->get(\PG\MSF\Client\Http\Client::class)
```
### 初始化對象
雖然我們使用了對象池模式,但我們也可以使用__construct()方法,無須額外調用初始化方法。
```
$this->getContext()->getObjectPool()->get(FeedComment::class, ['構造參數1', '構造參數2', ...]);
```
通常情況下,框架內置的類均`use MI;`,則可以直接使用`$this->getObject($className, ['構造參數列表'])`來創建對象,第三方lib也可使用trait來擴展類的功能。
### 資源釋放
className::destroy()
每一個類,理論上都需要定義destroy()方法,用于資源的手工釋放,但是不需要顯示調用,在請求結束時由框架自動調用。
對于和請求相關的數據,理論上我們是需要在請求結束后釋放相關資源,框架對于資源釋放的策略及優先級如下:
1. 響應請求后調用Controller::destroy()
2. 依次調用當前請求所使用的對象的destroy()方法
3. 將所有public的類屬性的值設置為初始值
通常情況下,destroy方法用于處理private,protected的類屬性,public由框架自動清理。
如下示例:
```php
<?php
/**
* Demo模型
*/
namespace App\Models;
use PG\MSF\Models\Model;
class Demo extends Model
{
public $pro1;
public $pro2;
protected $pro3;
private $pro4;
public function __construct($pro1, $pro2)
{
parent::__construct();
$this->pro1 = $pro1;
$this->pro2 = $pro2;
$this->pro3 = "protected";
$this->pro2 = "private";
}
public function getMockIds()
{
// 讀取配置后返回
return $this->getConfig()->get('params.mock_ids', []);
}
public function destroy()
{
parent::destroy();
$this->pro3 = null;
}
}
```
1. pro1,pro2屬性由框架自動在請求結束后賦值為初始值
2. pro3由業務手工在destroy()內清理
3. pro4長駐進程,永久使用
### 資源釋放級別
除了上述資源釋放策略,php-msf還提供自定義的資源釋放策略,只需要在獲取對象時提供第三個參數,如:
```php
function DS()
{
$this->getObject(Demo::class, [1, 2], \Marco::DS_PUBLIC | \Marco::DS_PROTECTED);
}
```
1. Marco::DS_PUBLIC 為默認策略
2. Marco::DS_PROTECTED 為釋放protected屬性
3. Marco::DS_PRIVATE 為釋放private屬性
4. Marco::DS_NONE 不釋放任何屬性
## 對象池實現原理

## PHP進程內存優化
對象池模式對PHP進程占用的內存優化可以說“完全超出預期”,如下圖所示:

上圖為近30天基于MSF重構的某業務其中一臺機器的一個worker進程內存占用的監控數據,從圖中有幾點:
1. 5-10~5-27,近15天內存占用波峰達1.25G,波谷的值在持續的攀升;
2. 5-27~5-31,近5天內存占用從一個較低的點持續攀升;
3. 6-01之后,內存占用持續穩定在25M上下小輻波動;
在1階段,框架大量類的對象是直接使用new關鍵字創建,完全依賴的PHP GC進行內存資源的回收;
在2階段,框架采用對象池的方案完全重構大量的邏輯,效果很明顯,但仍然有部分內存泄露;
在3階段,優化了業務邏輯,完全按照“資源釋放”的策略調整業務代碼,內存占用已穩定。
- 0 文檔說明
- 1 為什么研發新框架
- 1.1 傳統php-fpm工作模式的問題
- 1.2 壓測數據對比
- 1.3 小結
- 2 微服務框架研發概覽
- 2.1 通信框架技術選型
- 2.2 swoole
- 2.3 協程原理
- 2.4 異步、并發
- 2.5 小結
- 3 框架運行環境
- 3.1 環境變量
- 3.2 運行代碼
- 3.3 docker
- 3.4 小結
- 4 框架結構
- 4.1 結構概述
- 4.2 控制器
- 4.3 模型
- 4.4 視圖
- 4.5 同步任務
- 4.6 配置
- 4.7 路由
- 4.8 小結
- 5 框架組件
- 5.1 協程
- 5.2 類的加載
- 5.3 異步Http Client
- 5.4 請求上下文
- 5.5 連接池
- 5.6 對象池
- 5.7 RPC
- 5.8 公共庫
- 5.9 RESTful
- 5.10 多語言
- 5.11 雜項
- 5.12 小結
- 6 常見問題
- 7 附錄