色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

malloc和內存池技術的區別 內存池技術性能優化方案

電子設計 ? 來源:面包板社區 ? 作者:一口Linux ? 2021-03-02 15:29 ? 次閱讀

大家生活中肯定都有這樣的經驗,那就是大眾化的產品都比較便宜,但便宜的大眾產品就是一個詞,普通;而可以定制的產品一般都價位不凡,這種定制的產品注定不會在大眾中普及,因此定制產品就是一個詞,獨特。

有的同學可能會有疑問,你不是要聊技術嗎?怎么又說起消費了?

原來技術也有大眾貨以及定制品。

通用 VS 定制

作為程序員(C/C++)我們知道申請內存使用的是malloc,malloc其實就是一個通用的大眾貨,什么場景下都可以用,但是什么場景下都可以用就意味著什么場景下都不會有很高的性能。

malloc性能不高的原因一在于其沒有為特定場景做優化,除此之外還在于malloc看似簡單,但是其調用過程是很復雜的,一次malloc的調用過程可能需要經過操作系統的配合才能完成。 那么調用malloc時底層都發生了什么呢?簡單來說會有這樣典型的幾個步驟:

malloc開始搜索空閑內存塊,如果能找到一塊大小合適的就分配出去

如果malloc找不到一塊合適的空閑內存,那么調用brk等系統調用擴大堆區從而獲得更多的空閑內存

malloc調用brk后開始轉入內核態,此時操作系統中的虛擬內存系統開始工作,擴大進程的堆區,注意額外擴大的這一部分內存僅僅是虛擬內存,操作系統并沒有為此分配真正的物理內存

brk執行結束后返回到malloc,從內核態切換到用戶態,malloc找到一塊合適的空閑內存后返回

以上就是一次內存申請的完整過程,我們可以看到,一次內存申請過程其實是非常復雜的,關于這個問題的詳細討論你可以參考這里。 既然每次分配內存都要經過這么復雜的過程,那么如果程序大量使用malloc申請內存那么該程序注定無法獲得高性能。 幸好,除了大眾貨的malloc,我們還可以私人定制,也就是針對特定場景自己來維護內存申請和分配,這就是高性能高并發必備的內存池技術。

內存池技術有什么特殊的嗎? 有的同學可能會說,等等,那malloc和這里提到的內存池技術有什么區別呢? 第一個區別在于我們所說的malloc其實是標準庫的一部分,位于標準庫這一層;而內存池是應用程序的一部分。

其次在于定位,我們自己實現的malloc其實也是定位通用性的,通用性的內存分配器設計實現往往比較復雜,但是內存池技術就不一樣了,內存池技術專用于某個特定場景,以此優化程序性能,但內存池技術的通用性是很差的,在一種場景下有很高性能的內存池基本上沒有辦法在其它場景也能獲得高性能,甚至根本就不能用于其它場景,這就是內存池這種技術的定位。

那么內存池技術是怎樣優化性能的呢?

內存池技術原理 簡單來說,內存池技術一次性獲取到大塊內存,然后在其之上自己管理內存的申請和釋放,這樣就繞過了標準庫以及操作系統:

也就是說,通過內存池,一次內存的申請再也不用去繞一大圈了。 除此之外,我們可以根據特定的使用模式來進一步優化,比如在服務器端,每次用戶請求需要創建的對象可能就那幾種,那么這時我們就可以在自己的內存池上提前創建出這些對象,當業務邏輯需要時就從內存池中申請已經創建好的對象,使用完畢后還回內存池。 因此我們可以看到,這種為某些應用場景定制的內存池相比通用的比如malloc內存分配器會有大的優勢。 接下來我們就著手實現一個。

實現內存池的考慮 值得注意的是,內存池實際上有很多的實現方法,在這里我們還是以服務器端編程為例來說明。 假設你的服務器程序非常簡單,處理用戶請求時只使用一種對象(數據結構),那么最簡單的就是我們提前申請出一堆來,使用的時候拿出一個,使用完后還回去:

怎么樣,足夠簡單吧!這樣的內存池只能分配特定對象(數據結構),當然這樣的內存池需要自己維護哪些對象是已經被分配出去的,哪些是還沒有被使用的。 但是,在這里我們可以實現一個稍微復雜一些的,那就是可以申請不同大小的內存,而且由于是服務器端編程,那么一次用戶請求過程中我們只申請內存,只有當用戶請求處理完畢后一次性釋放所有內存,從而將內存申請釋放的開銷降低到最小。 因此,你可以看到,內存池的設計都是針對特定場景的。 現在,有了初步的設計,接下來就是細節了。

數據結構 為了能夠分配大小可變的對象,顯然我們需要管理空閑內存塊,我們可以用一個鏈表把所有內存塊鏈接起來,然后使用一個指針來記錄當前空閑內存塊的位置,如圖所示:

從圖中我們可以看到,有兩個空閑內存塊,空閑內存之間使用鏈表鏈接起來,每個內存塊都是前一個的2倍,也就是說,當內存池中的空閑內存不足以分配時我們就向malloc申請內存,只不過其大小是前一個的2倍:

其次,我們有一個指針free_ptr,指向接下來的空閑內存塊起始位置,當向內存池分配內存時找到free_ptr并判斷當前內存池剩余空閑是否足夠就可以了,有就分配出去并修改free_ptr,否則向malloc再次成倍申請內存。 從這里的設計可以看出,我們的內存池其實是不會提供類似free這樣的內存釋放函數的,如果要釋放內存,那么會一次性將整個內存池釋放掉,這一點和通用的內存分配器是不一樣。 現在,我們可以分配內存了,還有一個問題是所有內存池設計不得不考慮的,那就是線程安全,這個話題你可以參考這里。

線程安全 顯然,內存池不應該局限在單線程場景,那我們的內存池要怎樣實現線程安全呢? 有的同學可能會說這還不簡單,直接給內存池一把鎖保護就可以了。

這種方法是不是可行呢?還是那句話,It depends,要看情況。 如果你的程序有大量線程申請釋放內存,那么這種方案下鎖的競爭將會非常激烈,線程這樣的場景下使用該方案不會有很好的性能。 那么還有沒有一種更好的辦法嗎?答案是肯定的。

線程局部存儲 既然多線程使用線程池存在競爭問題,那么干脆我們為每個線程維護一個內存池就好了,這樣多線程間就不存在競爭問題了。 那么我們該怎樣為每個線程維護一個內存池呢? 線程局部存儲,Thread Local Storage正是用于解決這一類問題的,什么是線程局部存儲呢? 簡單說就是,我們可以創建一個全局變量,因此所有線程都可以使用該全局變量,但與此同時,我們將該全局變量聲明為線程私有存儲,那么這時雖然所有線程依然看似使用同一個全局變量,但該全局變量在每個線程中都有自己的副本,變量指向的值是線程私有的,相互之間不會干擾。

關于線程局部存儲,可以參考這里。 假設這個全局變量是一個整數,變量名字為global_value,初始值為100,那么當線程A將global_value修改為200時,線程B看到的global_value的值依然為100,只有線程A看到的global_value為200,這就是線程局部存儲的作用。

線程局部存儲+內存池 有了線程局部存儲問題就簡單了,我們可以將內存池聲明為線程局部存儲,這樣每個線程都只會操作屬于自己的內存池,這樣就再也不會有鎖競爭問題了。

注意,雖然這里給出了線程局部存儲的設計,但并不是說加鎖的方案就比不上線程局部存儲方案,還是那句話,一切要看使用場景,如果加鎖的方案夠用,那么我們就沒有必要絞盡腦汁的去用其它方案,因為加鎖的方案更簡單,代碼也更容易維護。 還需要提醒的是,這里只是給出了內存池的一種實現方法,并不是說所有內存池都要這么設計,內存池可以簡單也可復雜,一切要看實際場景,這一點也需要注意。

其它內存池形式 到目前為止我們給出了兩種內存池的設計方法,第一種是提前創建出一堆需要的對象(數據結構),自己維護好哪些對象(數據結構)可用哪些已被分配;第二種可以申請任意大小的內存空間,使用過程中只申請不釋放,最后一次性釋放。這兩種內存池天然適用于服務器端編程。 最后我們再來介紹一種內存池實現技術,這種內存池會提前申請出一大段內存,然后將這一大段內存切分為大小相同的小內存塊:

然后我們自己來維護這些被切分出來的小內存塊哪些是空閑的哪些是已經被分配的,比如我們可以使用棧這種數據結構,最初把所有空閑內存塊地址push到棧中,分配內存是就pop出來一個,用戶使用完畢后再push回棧里。

從這里的設計我們可以看出,這種內存池有一個限制,這個限制就是說程序申請的最大內存不能超過這里內存塊的大小,否則不足以裝下用戶數據,這需要我們對程序所涉及的業務非常了解才可以。 用戶申請到內存后根據需要將其塑造成特定對象(數據結構)。 關于線程安全的問題,可以同樣采用線程局部存儲的方式來實現:

一個有趣的問題 除了線程安全,這里還有一個非常有趣的問題,那就是如果線程A申請的對象被線程B拿去釋放,我們的內存池該怎么處理呢? 這個問題之所以有趣是因為我們必須知道該內存屬于哪個線程的局部存儲,但申請的內存本身并不能告訴你這樣的信息。 有的同學可能會說這還不簡單,不就是一個指針到另一個指針的映射嗎,直接用map之類存起來就好了,但問題并沒有這么簡單,原因就在于如果我們切分的內存塊很小,那么會存在大量內存塊,這就需要存儲大量的映射關系,有沒有辦法改進呢? 改進方法是這樣的,一般來說,我們申請到的大段內存其實是會按照特定大小進行內存對齊,我們假設總是按照4K字節對齊,那么該大段內存的起始地址后12個bit(4K = 2^12)為總是0,比如地址0x9abcd000,同時我們也假設申請到的大段內存大小也是4K:

那么我們就能知道該大段內存中的各個小內存塊起始地址除了后12個bit位外都是一樣的:

這樣拿到任意一個內存的地址我們就能知道對應的大段內存的起始地址,只需要簡單的將后12個bit置為0即可,有了大段內存的起始地址剩下的就簡單了,我們可以在大段內存中的最后保存對應的線程局部存儲信息:

這樣我們對任意一個內存塊地址進行簡單的位運算就可以得到對應的線程局部存儲信息,大大減少了維護映射信息對內存的占用。

總結 內存池是高性能服務器中常見的一種優化技術,在這里我們介紹了三種實現方法,值得注意的是,內存池實現沒有統一標準,一切都要根據具體場景定制,因此我們可以看到內存池設計是有針對性的,當然其反面就是不具備通用性。

編輯:hfy

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    3052

    瀏覽量

    74215
  • 局部存儲
    +關注

    關注

    0

    文章

    2

    瀏覽量

    5469
  • malloc
    +關注

    關注

    0

    文章

    53

    瀏覽量

    75
收藏 人收藏

    評論

    相關推薦

    hyper 內存,Hyper內存:如何監控與優化hyper-v虛擬機的內存使用

    :如何監控與優化hyper-v虛擬機的內存使用。 ? ?在虛擬化環境中,合理監控和優化Hyper-V虛擬機的內存使用對于提升性能和資源利用率
    的頭像 發表于 01-24 14:15 ?66次閱讀
    hyper <b class='flag-5'>內存</b>,Hyper<b class='flag-5'>內存</b>:如何監控與<b class='flag-5'>優化</b>hyper-v虛擬機的<b class='flag-5'>內存</b>使用

    DDR5內存與DDR4內存性能差異

    DDR5內存與DDR4內存性能差異 隨著技術的發展,內存技術也在不斷進步。DDR5
    的頭像 發表于 11-29 14:58 ?705次閱讀

    如何選擇DDR內存條 DDR3與DDR4內存區別

    隨著技術的不斷進步,計算機內存技術也在不斷發展。DDR(Double Data Rate)內存條作為計算機的重要組成部分,其性能直接影響到電
    的頭像 發表于 11-20 14:24 ?2573次閱讀

    HBM與GDDR內存技術全解析

    在高性能圖形處理領域,內存技術起著至關重要的作用。本文介紹兩種主要的圖形內存技術:高帶寬內存(H
    的頭像 發表于 11-15 10:47 ?1294次閱讀
    HBM與GDDR<b class='flag-5'>內存</b><b class='flag-5'>技術</b>全解析

    如何優化RAM內存使用

    優化RAM內存使用是一個重要的任務,特別是對于那些擁有有限內存資源的用戶。以下是一些優化RAM內存使用的策略,這些策略可以幫助您更有效地使用
    的頭像 發表于 11-11 09:58 ?517次閱讀

    污水處理預沉物聯網系統解決方案

    ,成為了當前水務行業的重要發展方向。 系統概述 對此,物通博聯提供基于工業智能網關的污水處理預沉物聯網系統解決方案,是基于物聯網技術,結合傳感器、PLC(可編程邏輯控制器)、無線通信等技術
    的頭像 發表于 10-09 10:39 ?255次閱讀
    污水處理預沉<b class='flag-5'>池</b>物聯網系統解決<b class='flag-5'>方案</b>

    離心溫度監測物聯網系統方案

    在現有技術的鋼丸生產工藝中,一般采用離心法實現鋼丸的成形,其原理是將熔融狀態的鋼水裝入離心機中,通過離心力將鋼水甩出離心機,離心機位于一個冷卻的中部,因此從離心機中甩出的鋼水落入冷卻池內的冷卻
    的頭像 發表于 09-20 10:56 ?205次閱讀
    離心<b class='flag-5'>池</b>溫度監測物聯網系統<b class='flag-5'>方案</b>

    什么是內存通道技術

    內存通道技術作為計算機系統中的核心組成部分,對于提升數據處理能力、優化系統性能以及增強系統的穩定性與擴展性等方面發揮著至關重要的作用。以下是對內存
    的頭像 發表于 09-04 12:47 ?776次閱讀

    買藥秒送 JADE動態線程實踐及原理淺析

    一、背景及JADE介紹 買藥秒送是健康即時零售業務新的核心流量場域,面對京東首頁高流量曝光,我們對頻道頁整個技術架構方案進行升級,保障接口高性能、系統高可用。 動態線程是買藥頻道應用
    的頭像 發表于 09-04 11:11 ?885次閱讀
    買藥秒送 JADE動態線程<b class='flag-5'>池</b>實踐及原理淺析

    buffers內存與cached內存區別

    free 命令是Linux系統上查看內存使用狀況最常用的工具,然而很少有人能說清楚 “buffers” 與 “cached” 之間的區別
    的頭像 發表于 07-29 14:17 ?554次閱讀
    buffers<b class='flag-5'>內存</b>與cached<b class='flag-5'>內存</b>的<b class='flag-5'>區別</b>

    使用rt_malloc申請內存空間失敗,顯示沒有內存怎么解決?

    + net_server + crclib) 的情況下,還有2個堆棧空間2048的應用線程,使用rt_malloc申請內存空間失敗,顯示沒有內存。經測試,只能申請1200bytes 以下的
    發表于 07-04 08:10

    OpenHarmony語言基礎類庫【@ohos.taskpool(啟動任務)】

    建的任務進行如任務執行、任務取消的操作。理論上您可以使用任務API創建數量不受限制的任務,但是出于內存因素不建議您這樣做。此外,不建議您在任務中執行阻塞操作,特別是無限期阻塞操作,長時間的阻塞操作占據工作線程,可能會阻塞其他任務調度,影響您的應用
    的頭像 發表于 04-24 17:45 ?383次閱讀
    OpenHarmony語言基礎類庫【@ohos.taskpool(啟動任務<b class='flag-5'>池</b>)】

    可以在RTOS的任何位置使用malloc申請內存了嗎?

    今天看了CubeIDE 1.7.0的release note ,里面寫的一條新特性是:Thread-safe malloc solution 這是否意味著我可以在RTOS的任何位置使用malloc申請內存了?
    發表于 04-03 07:23

    C語言內存泄漏問題原理

    內存泄漏問題只有在使用堆內存的時候才會出現,棧內存不存在內存泄漏問題,因為棧內存會自動分配和釋放。C語言代碼中堆
    發表于 03-19 11:38 ?567次閱讀
    C語言<b class='flag-5'>內存</b>泄漏問題原理

    什么是動態線程?動態線程的簡單實現思路

    因此,動態可監控線程一種針對以上痛點開發的線程管理工具。主要可實現功能有:提供對 Spring 應用內線程實例的全局管控、應用運行時動態變更線程參數以及線程
    的頭像 發表于 02-28 10:42 ?691次閱讀
    主站蜘蛛池模板: vagaa哇嘎黄短片 | 偷上邻居熟睡少妇 | 亚洲野狼综合网站 | 久久成人永久免费播放 | 久久久久久久国产精品视频 | 久久亚洲精品AV成人无 | 亚洲精品电影久久久影院 | 囯产免费久久久久久国产免费 | 帅哥男男GV在线1080P | 久久久久亚洲日日精品 | 久久伊人免费 | 亚洲国产精品无码AV久久久 | 亚洲免费视频观看 | 人妻免费视频公开上传 | 亚洲国产成人爱AV在线播放丿 | 成人区在线观看免费视频 | 囯产精品一区二区三区线 | 秘密影院久久综合亚洲综合 | 99国产精品偷窥熟女精品视频 | 久久人妻AV一区二区软件 | 国产成人永久免费视频 | 色狠狠色综合吹潮 | 国产日韩在线欧美视频 | 伊人久久青草青青综合 | 99久久精品毛片免费播放 | 91麻豆国产精品91久久久 | bl被教练啪到哭H玉势 | 欧美亚洲日韩国码在线观看 | 国产人妻精品午夜福利免费不卡 | 亚洲qvod图片区电影 | 18女下面流水不遮网站免费 | 女人操男人 | 久久99综合国产精品亚洲首页 | 国产情侣真实露脸在线 | 一二三四韩国免费观看 | 久久青草在线视频精品 | 天上人间影院久久国产 | 公粗挺进了我的密道在线播放贝壳 | 国产欧美一本道无码 | 日韩精品卡1卡2三卡四卡乱码 | 国产精品成人影院在线观看 |