這么小改一下,PHP json_decode內存節省70%

如果你用PHP的json_decode函數解析JSON串,而且JSON串中包含一個大量元素的數組,那你就要小心解析過程中PHP超出內存上限了。

筆者在開發時遇到一個JSON文件需要解析,該JSON中包含了一個由眾多MAC地址組成的數組,像這樣:

{
    "name": "MAC File",
    "date": "2017-11-08",
    "macList": [
        "11-11-11-11-11-11",
        "22-22-22-22-22-22",
        ...
    ]
}

結果json_decode過程中超出了PHP默認的128M內存上限。

WHAT,超限了?!這個JSON文件才 10M 啊!

在大罵“這函數是不是有BUG”之后,仔細推敲下,發現問題出在MAC地址構成的數組上。要知道PHP的數組是很吃內存的。

PHP數組究竟多吃內存,可以做個簡單的試驗,向數組內放入50萬個MAC地址,打印內存占用量:

$a = [];
for ($i = 0; $i !== 500000; $i++) {
    $a[] = '11-11-11-11-11-11';
}
echo memory_get_usage() . PHP_EOL;

如果把這些MAC地址寫在一個文件里,理論上只占 9.6M 磁盤空間,但是PHP數組維護相同的信息,卻占了 72.4M 內存 。

有辦法解決json_deocde時的內存超限嗎?當然,簡單粗暴點的話就把內存上限調高:

ini_set('memory_limit','1024M');

雖然可行,但會引發一個問題,就是:

可能被其他語言的工程師嘲笑PHP占內存。

那有沒有更明智的辦法解決內存超限問題?

有。因為PHP數組占用內存很大,所以我們要避免json_decode在解碼時產生巨大數組。怎么做呢?這就要從JSON的編碼格式下手,比如可以把巨大的JSON數組修改成字符串:

{
    "name": "MAC File",
    "date": "2017-11-08",
    "macList": "11-11-11-11-11-11,22-22-22-22-22-22,...",
}

我把macList從數組轉換成以逗號分割的字符串。這樣可以避免json_decde產生一個巨大無比的數組,取而代之的是一個超長的字符串。

字符串占用的內存量可比數組小多了,剛才50萬個MAC地址,瞬間只占9.7M的內存。修改完之后,json_decode順利解析成功,而且解析速度更快了。

原先macList是個數組,可以通過foreach遍歷其中的元素,現在是字符串了,該怎么遍歷呢?

不難,可以用strtok

$tok = strtok($macList, ',');
while ($tok !== false) {
    $mac = $tok;
    $tok = strtok(',');
}

遍歷的難度沒有增加多少,是吧?

你可能會問,這種方法可以對付簡單的JSON數組,如果一個JSON數組的每個元素是個JSON對象,該怎么辦?

我們可以這樣構造字符串:

{
    "list": '{"name":"obj1"}###{"name":"obj2"}###...'
}

字符串由一個個小的JSON組成,它們之間用特殊的標記###分割。在解析時,根據特殊標記切分出一個個JSON對象,再用json_decode逐個解析:

$tok = strtok($objectList, '###'); // 按###切割
while ($tok !== false)
{
    $objectStr = $tok;
     // 每切割出一個JSON對象就解碼
    $object = json_decode($objectStr, true);
    $tok = strtok('###');
}

你也可以自創一種編碼/解析這個超長字符串的方法,總之最終目標就是避免json_decode在解碼過程中產生超大數組。

通過本文,你應該略到了PHP Array吃內存的能力。把JSON中的數組替換成字符串表示,可以節省大量的內存。我還跑了一個對比數據,給大家參考:

解析50萬個MAC

保存MAC地址方式 數組方式 字符串方式
JSON文件大小 9.6M 8.6M(每個元素省了一對引號)
平均內存占用 72.4M 8.7M
平均json_decode解析時間 0.73s 0.41s

解析100萬個MAC:

保存MAC地址方式 數組方式 字符串方式
JSON文件大小 20M 18M
平均內存占用 204.6M 54.2M
平均json_decode解析時間 1.61s 0.81s

解析200萬個MAC:

保存MAC地址方式 數組方式 字符串方式
JSON文件大小 40M 36M
平均內存占用 409.0M 108.2M
平均json_decode解析時間 3.05s 1.53s

如果對您的工作有幫助,還請幫忙點個贊:-)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Swift版本點擊這里歡迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh閱讀 25,528評論 7 249
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,881評論 18 139
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,202評論 4 61
  • PHP 學習目錄 ├─PHP視頻教程 1 LAMP網站構建 │ ├─PHP教程 1.1.1 新版視頻形式介紹│ ...
    曹淵說創業閱讀 16,175評論 29 417
  • 無疑,這是一個悲劇,以近乎諷刺的喜開頭,以大快人心的悲結尾,中間是接連不斷地任人擺布,這只擺布的手來自命運。 故事...
    東流水酌月閱讀 514評論 0 0