性能優化-放開那片內存,讓我來!

2021-03-02 良許Linux

性能優化是一個常有的事情,通常來說

本人對此沒有過多涉獵,僅分享工作中接觸到的一些內存。

內存性能問題

有很多方面會造成性能問題,例如:

業務流程設計不合理,導致很多沒有必要的計算

數據結構選擇不合適

緩存使用不當

示例

假設你已經者使用profiler分析,已經發現內存分配是性能瓶頸:

// 來源:公眾號【編程珠璣】
// 作者:守望先生
// malloc.cc
#include <thread>
#include <vector>
#include <stdlib.h>
#include <string.h>
void GetMemory(){
  for(int i = 0;i < 100000000; i++){
    void *p = malloc(1024);
    if(NULL != p){
      free(p);
      p = NULL;
    }
  }
}
int main(){
  std::vector<std::thread> th;
  int nr_threads = 10;
  for (int i = 0; i < nr_threads; ++i) {
    th.push_back(std::thread(GetMemory));
  }
  for(auto &t : th){
    t.join();
  }
  return 0;
}

代碼非常簡單,僅僅是不斷分配內存而已。

編譯並嘗試分配十億次:

$ g++ -g -o malloc malloc.cc -lpthread
$ time ./malloc 
real    0m8.677s
user    0m29.409s
sys    0m0.029s

分配十億次內存,使用時間大概17s左右。另外一個終端使用perf查看情況:

$ perf top -p `pidof malloc`
  52.92%  libc-2.27.so  [.] cfree@GLIBC_2.2.5
  31.94%  libc-2.27.so  [.] malloc
   8.82%  malloc        [.] GetMemory
   3.45%  malloc        [.] free@plt
   2.51%  malloc        [.] malloc@plt
   0.03%  [kernel]      [k] prepare_exit_to_usermode
   0.01%  [kernel]      [k] psi_task_change
   0.01%  [kernel]      [k] native_irq_return_iret
   0.01%  [kernel]      [k] __update_load_avg_cfs_rq
   0.01%  [kernel]      [k] __update_load_avg_se
   0.01%  [kernel]      [k] update_curr
   0.01%  [kernel]      [k] native_write_msr
   0.01%  [kernel]      [k] __schedule
   0.01%  [kernel]      [k] native_read_msr
   0.01%  [kernel]      [k] read_tsc
   0.01%  [kernel]      [k] interrupt_entry
   0.01%  [kernel]      [k] update_load_avg
   0.01%  [kernel]      [k] swapgs_restore_regs_and_return_to_usermode
   0.01%  [kernel]      [k] reweight_entity
   0.01%  [kernel]      [k] switch_fpu_return
   0.01%  [kernel]      [k] perf_event_task_tick

從結果可以看到,大部分CPU耗費在了內存的申請和釋放。

怎麼辦呢?第一要考慮的做法不是如何提升它,而是它能否避免?比如內存復用?而非反覆申請?
比如使用內存池?但是要自己寫一個穩定的內存池又需要耗費很大的精力了。怎麼辦呢?

性能更好的庫

實際上這就引出了性能優化的一種常見方法-使用性能更好的庫。那麼在內存分配方面,有更好的庫嗎?自己又不能寫出一個比libc還厲害的庫,就只能用用開源的庫,才能維持得了寫代碼的生活。

目前常見的性能比較好的內存分配庫有

tcmalloc-谷歌開發的內存分配庫

jemalloc

在自己編譯使用redis的時候,其實你能看到它們的身影:

# Backwards compatibility for selecting an allocator
ifeq ($(USE_TCMALLOC),yes)
    MALLOC=tcmalloc
endif

ifeq ($(USE_TCMALLOC_MINIMAL),yes)
    MALLOC=tcmalloc_minimal
endif

ifeq ($(USE_JEMALLOC),yes)
    MALLOC=jemalloc
endif

ifeq ($(USE_JEMALLOC),no)
    MALLOC=libc
endif

如何使用

這裡以tcmalloc為例,看一下如何使用該庫替換libc中的malloc。tcmalloc使用了thread cache,小塊的內存分配都可以從cache中分配。多線程分配內存的情況下,可以減少鎖競爭。

獲取

你可以通過源碼編譯獲取,github地址:https://github.com/google/tcmalloc.git
不過它需要使用bazel進行構建編譯,有興趣的可以自行嘗試。

也可以直接安裝:

$ apt-get install -y libtcmalloc-minimal4

安裝位置查看:

$ ldconfig -p | grep tcmalloc
    libtcmalloc_minimal_debug.so.4 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libtcmalloc_minimal_debug.so.4
    libtcmalloc_minimal.so.4 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libtcmalloc_minimal.so.4
    libtcmalloc_debug.so.4 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libtcmalloc_debug.so.4
    libtcmalloc_and_profiler.so.4 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libtcmalloc_and_profiler.so.4
    libtcmalloc.so.4 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libtcmalloc.so.4

LD_PRELOAD

這種方式在自己測試的時候非常方便,只需要:

$ export LD_PRELOAD=/path/to/tcmalloc.so

導入環境變量,指定庫路徑即可。注意這裡的/path/to更換成你的tcmalloc實際的路徑。運行的時候,tcmalloc庫就會被首先被使用了。

直接連結

這種方法就和普通庫的使用沒有什麼區別了,連結使用就完事了。

效果

我們使用新的庫,再進行10億次的內存分配試試:

$ time ./malloc
real    0m7.152s
user    0m27.997s
sys    0m0.032s

可以看到要使用的時間少了些。當然,這裡的對比嚴格來說不是很嚴謹,甚至可以說起不到對比的作用。首先這裡內存分配大小比較單一,並且僅有內存分配,而沒有其他處理,真正是否有效果,還是要根據實際業務程序的情況來判斷。當然,整體來說,tcmalloc的效果要比libc的malloc分配內存要高效。

總結

當你的程序中存在大量的內存分配(例如C++頻繁使用string),那麼可以考慮使用性能更好的內存分配庫了。關於tcmalloc,jemalloc等內存分配庫的對比有很多,這裡有興趣的可自行了解。

添加良許個人微信即送3套程式設計師必讀資料

→ 精選技術資料共享

→ 高手如雲交流社群

本公眾號全部博文已整理成一個目錄,請在公眾號裡回復「m」獲取!

推薦閱讀:

是時候跟Docker說再見了

Linux系統inodes資源耗盡問題

如何從一張外國軍車照片,判斷它要去哪裡?

5T技術資源大放送!包括但不限於:C/C++,Linux,Python,Java,PHP,人工智慧,單片機,樹莓派,等等。在公眾號內回復「1024」,即可免費獲取!!

相關焦點

  • Android性能優化--內存優化
    本文來自Dotry投稿,連結:https://www.jianshu.com/p/38b627adaecd上一篇文章關於Android性能優化--啟動優化探討了啟動優化相關的知識點,在本篇將介紹內存優化的相關優化。
  • Android性能優化:帶你全面實現內存優化
    本文主要講解性能優化中的內存優化,希望你們會喜歡目錄1.常見的內存問題 & 優化方案常見的內存問題如下內存洩露內存抖動圖片Bitmap相關代碼質量 & 數量日常不正確使用下面,我將詳細分析每項的內存問題 & 給出優化方案4.1 內存洩露簡介即 ML
  • Android性能優化:手把手帶你全面實現內存優化
    最近有想換工作的同學們,可參考《5月技術崗位內推|RN開發招聘啦》,再往下看,一篇關於性能優化的好文章,很值得去學習。前言在 Android開發中,性能優化策略十分重要本文主要講解性能優化中的內存優化,希望你們會喜歡目錄
  • 高頻面試點:Android性能優化之內存優化(上篇)
    眾所周知,內存優化可以說是性能優化中最重要的優化點之一,可以說,如果你沒有掌握系統的內存優化方案,就不能說你對Android的性能優化有過多的研究與探索。本篇,筆者將帶領大家一起來系統地學習Android中的內存優化。
  • Android性能優化總結
    這是來自一位粉絲「MeloDev」的投稿,講真,我這裡投稿的不少,但是只有我自己覺得很不錯的才會通過,這篇文章我覺得對大家有用,而且性能優化也算是我面試必問的一個話題了,所以這裡推薦給大家。網絡:頻繁的網絡訪問會導致耗電和影響應用的性能;網絡交互數據大小會影響網絡傳輸的效率;5. 程序執行效率:糟糕的代碼會嚴重影響程序的運行效率,UI線程過多的任務會阻塞應用的正常運行,長時間持有某個對象會導致潛在的內存洩露,頻繁的IO操作、網絡操作而不用緩存會嚴重影響程序的運行效率。
  • Android 性能優化之內存洩漏,使用MAT&LeakCanary解決問題
    本文較長,閱讀大約5分鐘App進行到最終的測試的時候,往往會出現一些性能上,以及內存上的問題,需要優化,這也是一個Android高級工程師所需要了解並且掌握的知識點
  • 系統架構性能優化思路
    比如我們常見的JVM堆內存溢出,如果程序代碼沒有內存洩漏問題的話,我就需要考慮調整JVM啟動時候堆內存設置。在32位作業系統下只能夠設置到4G,但是在64位作業系統下已經可以設置到8G甚至更大的值。對於JVM內存溢出問題,我前面寫過一篇專門的分析文章可以參考。
  • 最全的Android內存優化技巧
    本文主要介紹性能優化的一些手段,但是為了便於理解以及融會貫通,建議先了解Android內存管理機制,本文將從四個角度來介紹內存優化技巧減小對象的內存佔用儘量減少新分配出來的對象佔用內存的大小,使用更加輕量的對象1.
  • 性能優化之PHP優化
    在我們平常寫代碼的過程中,除了資料庫的優化,針對與文件的優化,我們還需要對PHP執行優化,當然對於老司機來說,這都是毛毛雨咯~但是畢竟有新手嘛,於是,我整理這麼一片文章。(未完待續...)性能優化之PHP優化(一):PHP結構1.字符串
  • android內存優化總結
    所以PSS值除了自身應用佔有的內存外還包括共享內存中比例分配到單個應用身上的內存,所以我覺得用這個值來定義是否進行了優化是比較合適的。使用核心然後再退出的功能,查看PSS值是否飆升或者在使用後長時間不降低下來如果遇到飆升雖然後續能降低下來,但是依然有可能OOM,這樣我們也需要去追查是什麼原因了,看如何能夠減少內存的使用。
  • 緩存永遠不是性能優化
    還記得用彙編和C語言來編寫代碼的那段日子,我不得不做一套自己的內存管理系統,這樣我編寫的代碼可以在4K的RAM上運行,雖然這樣,仍然是令人稱讚的。如今,有許多人喜歡拼湊代碼片段然後再進行調用,我曾也是這種黑客裡面的一員,但後來我決定要「改過自新」,好好學習編程知識。如今我已經學習許多概念、設計模型,當我回去看以前那種麵條式代碼時,真心讓我反胃。
  • 程序丨Unity3D性能優化最佳實踐(二):內存
    作者:Ian  翻譯: Kelvin Lo / 海龜系列回顧:Unity3D性能優化最佳實踐(一):分析
  • 前端性能優化之利用 Chrome Dev Tools 性能分析
    來開發調試,但是很少知道怎麼利用它來分析頁面性能,這篇文章,我將詳細說明怎樣利用 Chrome Dev Tools 進行頁面性能分析及性能報告數據如何解讀。如果你認真看了本文,一定能學會分析,沒學會,你來找我~上圖是 Chrome Dev Tools 的一個截圖,其中,我認為能用於進行頁面性能快速分析的主要是圖中圈出來的幾個模塊功能,這裡簡單介紹一下:Network : 頁面中各種資源請求的情況,這裡能看到資源的名稱
  • PHP7革新與性能優化
    有幸參與2015年的PHP技術峰會(PHPCON),聽了鳥哥(惠新宸)的關於PHP7的新特性和性能優化的分享,一切都令人感到激動。鳥哥是國內最權威的PHP專家,他的分享有很多非常有價值的東西,我通過整理分享的PPT和收集相關資料,整理為這篇解讀性質的技術文章,希望能給做PHP開發的同學一些幫助。
  • 美國網站伺服器性能優化的方法
    提高美國網站伺服器的性能,以最大限度的利用率實現利益的最大化,這是很多美國網站伺服器用戶所希望達到的效果,因此美國網站伺服器的的性能優化是非常重要且必要的工作。今天小編就來分享下美國網站伺服器性能優化的方法。
  • Android性能優化典範
    摘要:Google在Udacity上的《Android性能優化》在線課程詳細介紹了該如何優化性能,這些課程是Google之前在Youtube上發布的Android性能優化典範專題課程的細化與補充。本文是對渲染、運算、內存、電量四個篇章的學習筆記。
  • 前端性能優化之利用 Chrome Dev Tools 進行頁面性能分析
    來開發調試,但是很少知道怎麼利用它來分析頁面性能,這篇文章,我將詳細說明怎樣利用 Chrome Dev Tools 進行頁面性能分析及性能報告數據如何解讀。如果你認真看了本文,一定能學會分析,沒學會,你來找我~上圖是 Chrome Dev Tools 的一個截圖,其中,我認為能用於進行頁面性能快速分析的主要是圖中圈出來的幾個模塊功能,這裡簡單介紹一下:Network : 頁面中各種資源請求的情況,這裡能看到資源的名稱
  • Spark性能優化指南——基礎篇
    因此,想要用好Spark,就必須對其進行合理的性能優化。Spark的性能調優實際上是由很多部分組成的,不是調節幾個參數就可以立竿見影提升作業性能的。我們需要根據不同的業務場景以及數據情況,對Spark作業進行綜合性的分析,然後進行多個方面的調節和優化,才能獲得最佳性能。
  • go 性能優化之 benchmark + pprof
    就這麼一點點的區別,性能能差多少呢?讓我們把懸念留到最後。benchmark 實施假設當前項目中的代碼就是二師兄寫的,我們就來分析一下,當前的性能瓶頸到底在什麼地方。到這裡,我們其實已經完成了基準測試的一個基本流程,也對二師兄的加密函數的性能和內存使用狀況有了一個初步的認識。但是,我們還是不知道性能瓶頸在哪!!終極殺器:benchmark + pprofpprof 是 go 自帶的 CPU 分析器,常用來分析性能瓶頸。
  • 高並發場景下如何優化伺服器的性能?
    也有小夥伴說問我。那今天,我們就來根據這個問題來聊聊在高並發場景下如何優化伺服器的性能這個話題。tcp_nodelay參數主要是對TCP套接字來說的,那對於伺服器硬體,如果要使其能夠支撐上百萬甚至上千萬的並發,我們該如何對其進行優化呢?