首頁 系統教程 Linux 優化curl的記憶體分配操作

優化curl的記憶體分配操作

Dec 27, 2023 pm 02:23 PM
linux linux教程 紅帽 linux系統 linux指令 linux認證 紅帽linux linux視頻

今天我在 libcurl 內部又做了一個小改動[1],使其做更少的 malloc。這一次,泛型鍊錶函數被轉換成更少的 malloc (這才是鍊錶函數應有的方式,真的)。

研究 malloc

幾週前我開始研究記憶體分配。這很容易,因為多年前我們 curl 就已經有記憶體調試和日誌記錄系統了。使用 curl 的偵錯版本,並在我的建置目錄中執行此腳本:

#!/bin/sh
export CURL_MEMDEBUG=$HOME/tmp/curlmem.log
./src/curl http://localhost
./tests/memanalyze.pl -v $HOME/tmp/curlmem.log
登入後複製

對於 curl 7.53.1,這大約有 115 次記憶體分配。這算多還是少?

記憶體日誌非常基礎。為了讓你有所了解,這是一個範例片段:

MEM getinfo.c:70 free((nil))
MEM getinfo.c:73 free((nil))
MEM url.c:294 free((nil))
MEM url.c:297 strdup(0x559e7150d616) (24) = 0x559e73760f98
MEM url.c:294 free((nil))
MEM url.c:297 strdup(0x559e7150d62e) (22) = 0x559e73760fc8
MEM multi.c:302 calloc(1,480) = 0x559e73760ff8
MEM hash.c:75 malloc(224) = 0x559e737611f8
MEM hash.c:75 malloc(29152) = 0x559e737a2bc8
MEM hash.c:75 malloc(3104) = 0x559e737a9dc8
登入後複製
檢查日誌

然後,我對日誌進行了更深入的研究,我意識到在相同的程式碼行做了許多小記憶體分配。我們顯然有一些相當愚蠢的程式碼模式,我們分配一個結構體,然後將該結構添加到鍊錶或哈希,然後該程式碼隨後再添加另一個小結構體,如此這般,而且經常在循環中執行。 (我在這裡說的是我們,不是為了責怪某個人,當然大部分的責任是我自己…)

這兩種分配操作將總是成對地出現,並同時釋放。我決定解決這些問題。做非常小的(小於 32 位元組)的分配也是浪費的,因為非常多的資料將被用於(在 malloc 系統內)追蹤那個微小的記憶體區域。更不用說堆碎片了。

因此,將該雜湊和鍊錶程式碼修復為不使用 malloc 是快速且簡單的方法,對於最簡單的 “curl http://localhost” 傳輸,它可以消除 20% 以上的 malloc。

此時,我根據大小對所有的記憶體分配操作進行排序,並檢查所有最小的分配操作。一個突出的部分是在curl_multi_wait() 中,它是一個典型的在 curl 傳輸主循環中被反覆呼叫的函數。對於大多數典型情況,我將其轉換為使用堆疊[2]。在大量重複的呼叫函數中避免 malloc 是一件好事。

重新計數

現在,如上面的腳本所示,同樣的 curl localhost 指令從 curl 7.53.1 的 115 次分配操作下降到 80 個分配操作,而沒有犧牲任何東西。輕鬆地有 26% 的改善。一點也不差!

由於我修改了 curl_multi_wait(),我也想看看它實際上是如何改進一些稍微更高級一些的傳輸。我使用了multi-double.c[3] 範例程式碼,添加了初始化記憶體記錄的調用,讓它使用curl_multi_wait(),並且並行下載了這兩個URL:

http://www.example.com/
http://localhost/512M
登入後複製

第二個檔案是 512 兆位元組的零,第一個檔案是一個 600 位元組的公共 html 頁面。這是 count-malloc.c 程式碼[4]

首先,我使用 7.53.1 來測試上面的例子,並使用 memanalyze 腳本檢查:

Mallocs: 33901
Reallocs: 5
Callocs: 24
Strdups: 31
Wcsdups: 0
Frees: 33956
Allocations: 33961
Maximum allocated: 160385
登入後複製

好了,所以它總共使用了 160KB 的內存,分配操作次數超過 33900 次。而它下載超過 512 兆位元組的數據,所以它每 15KB 數據有一次 malloc。是好是壞?

回到 git master,現在是 7.54.1-DEV 的版本 - 因為我們不太確定當我們發布下一個版本時會變成哪個版本號。它可能是 7.54.1 或 7.55.0,它還尚未確定。我離題了,我再次運行相同修改的 multi-double.c 範例,再次對記憶體日誌運行 memanalyze,報告來了:

Mallocs: 69
Reallocs: 5
Callocs: 24
Strdups: 31
Wcsdups: 0
Frees: 124
Allocations: 129
Maximum allocated: 153247
登入後複製

我不敢置信地重複看了兩次。發生什麼事了嗎?為了仔細檢查,我最好再運行一次。無論我運行多少次,結果還是一樣的。

33961 vs 129

在典型的傳輸中curl_multi_wait() 被呼叫了很多次,並且在傳輸過程中至少要正常進行一次記憶體分配操作,因此刪除那個單一的微小分配操作對計數器有非常大的影響。正常的傳輸也會做一些將資料移入或移出鍊錶和雜湊操作,但是它們現在也大都是無 malloc 的。簡單來說:剩餘的分配操作不會在傳輸循環中執行,所以它們的重要性不大。

先前的 curl 是目前範例分配操作數量的 263 倍。換句話說:新的是舊的分配操作數量的 0.37% 。

另外还有一点好处,新的内存分配量更少,总共减少了 7KB(4.3%)。

malloc 重要吗?

在几个 G 内存的时代里,在传输中有几个 malloc 真的对于普通人有显著的区别吗?对 512MB 数据进行的 33832 个额外的 malloc 有什么影响?

为了衡量这些变化的影响,我决定比较 localhost 的 HTTP 传输,看看是否可以看到任何速度差异。localhost 对于这个测试是很好的,因为没有网络速度限制,更快的 curl 下载也越快。服务器端也会相同的快/慢,因为我将使用相同的测试集进行这两个测试。

我相同方式构建了 curl 7.53.1 和 curl 7.54.1-DEV,并运行这个命令:

curl http://localhost/80GB -o /dev/null
登入後複製

下载的 80GB 的数据会尽可能快地写到空设备中。

我获得的确切数字可能不是很有用,因为它将取决于机器中的 CPU、使用的 HTTP 服务器、构建 curl 时的优化级别等,但是相对数字仍然应该是高度相关的。新代码对决旧代码!

7.54.1-DEV 反复地表现出更快 30%!我的早期版本是 2200MB/秒增加到当前版本的超过 2900 MB/秒。

这里的要点当然不是说它很容易在我的机器上使用单一内核以超过 20GB/秒的速度来进行 HTTP 传输,因为实际上很少有用户可以通过 curl 做到这样快速的传输。关键在于 curl 现在每个字节的传输使用更少的 CPU,这将使更多的 CPU 转移到系统的其余部分来执行任何需要做的事情。或者如果设备是便携式设备,那么可以省电。

关于 malloc 的成本:512MB 测试中,我使用旧代码发生了 33832 次或更多的分配。旧代码以大约 2200MB/秒的速率进行 HTTP 传输。这等于每秒 145827 次 malloc - 现在它们被消除了!600 MB/秒的改进意味着每秒钟 curl 中每个减少的 malloc 操作能额外换来多传输 4300 字节。

去掉这些 malloc 难吗?

一点也不难,非常简单。然而,有趣的是,在这个旧项目中,仍然有这样的改进空间。我有这个想法已经好几年了,我很高兴我终于花点时间来实现。感谢我们的测试套件,我可以有相当大的信心做这个“激烈的”内部变化,而不会引入太可怕的回归问题。由于我们的 API 很好地隐藏了内部,所以这种变化可以完全不改变任何旧的或新的应用程序……

(是的,我还没在版本中发布该变更,所以这还有风险,我有点后悔我的“这很容易”的声明……)

注意数字

curl 的 git 仓库从 7.53.1 到今天已经有 213 个提交。即使我没有别的想法,可能还会有一次或多次的提交,而不仅仅是内存分配对性能的影响。

还有吗?

还有其他类似的情况么?

也许。我们不会做很多性能测量或比较,所以谁知道呢,我们也许会做更多的愚蠢事情,我们可以收手并做得更好。有一个事情是我一直想做,但是从来没有做,就是添加所使用的内存/malloc 和 curl 执行速度的每日“监视” ,以便更好地跟踪我们在这些方面不知不觉的回归问题。

补遗,4/23

(关于我在 hacker news、Reddit 和其它地方读到的关于这篇文章的评论)

有些人让我再次运行那个 80GB 的下载,给出时间。我运行了三次新代码和旧代码,其运行“中值”如下:

旧代码:

real    0m36.705s
user    0m20.176s
sys     0m16.072s
登入後複製

新代码:

real    0m29.032s
user    0m12.196s
sys     0m12.820s
登入後複製

承载这个 80GB 文件的服务器是标准的 Apache 2.4.25,文件存储在 SSD 上,我的机器的 CPU 是 i7 3770K 3.50GHz 。

有些人也提到 alloca() 作为该补丁之一也是个解决方案,但是 alloca() 移植性不够,只能作为一个孤立的解决方案,这意味着如果我们要使用它的话,需要写一堆丑陋的 #ifdef


以上是優化curl的記憶體分配操作的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1328
25
PHP教程
1273
29
C# 教程
1253
24
Linux體系結構:揭示5個基本組件 Linux體系結構:揭示5個基本組件 Apr 20, 2025 am 12:04 AM

Linux系統的五個基本組件是:1.內核,2.系統庫,3.系統實用程序,4.圖形用戶界面,5.應用程序。內核管理硬件資源,系統庫提供預編譯函數,系統實用程序用於系統管理,GUI提供可視化交互,應用程序利用這些組件實現功能。

git怎麼查看倉庫地址 git怎麼查看倉庫地址 Apr 17, 2025 pm 01:54 PM

要查看 Git 倉庫地址,請執行以下步驟:1. 打開命令行並導航到倉庫目錄;2. 運行 "git remote -v" 命令;3. 查看輸出中的倉庫名稱及其相應的地址。

notepad怎麼運行java代碼 notepad怎麼運行java代碼 Apr 16, 2025 pm 07:39 PM

雖然 Notepad 無法直接運行 Java 代碼,但可以通過借助其他工具實現:使用命令行編譯器 (javac) 編譯代碼,生成字節碼文件 (filename.class)。使用 Java 解釋器 (java) 解釋字節碼,執行代碼並輸出結果。

sublime寫好代碼後如何運行 sublime寫好代碼後如何運行 Apr 16, 2025 am 08:51 AM

在 Sublime 中運行代碼的方法有六種:通過熱鍵、菜單、構建系統、命令行、設置默認構建系統和自定義構建命令,並可通過右鍵單擊項目/文件運行單個文件/項目,構建系統可用性取決於 Sublime Text 的安裝情況。

Linux的主要目的是什麼? Linux的主要目的是什麼? Apr 16, 2025 am 12:19 AM

Linux的主要用途包括:1.服務器操作系統,2.嵌入式系統,3.桌面操作系統,4.開發和測試環境。 Linux在這些領域表現出色,提供了穩定性、安全性和高效的開發工具。

laravel安裝代碼 laravel安裝代碼 Apr 18, 2025 pm 12:30 PM

要安裝 Laravel,需依序進行以下步驟:安裝 Composer(適用於 macOS/Linux 和 Windows)安裝 Laravel 安裝器創建新項目啟動服務訪問應用程序(網址:http://127.0.0.1:8000)設置數據庫連接(如果需要)

git軟件安裝 git軟件安裝 Apr 17, 2025 am 11:57 AM

安裝 Git 軟件包括以下步驟:下載安裝包運行安裝包驗證安裝配置 Git安裝 Git Bash(僅限 Windows)

sublime快捷鍵怎麼使用 sublime快捷鍵怎麼使用 Apr 16, 2025 am 08:57 AM

Sublime Text 提供了提高开发效率的快捷键,包括常用的(保存、复制、剪切等)、编辑(缩进、格式化等)、导航(项目面板、文件浏览等)以及查找和替换快捷键。熟练使用这些快捷键可显著提升 Sublime 的使用效率。

See all articles