1. 程式人生 > >專案中Map端記憶體佔用的分析

專案中Map端記憶體佔用的分析

最近在專案中開展重構活動,對Map端記憶體儘量要省一些,當前的系統中Map端記憶體最高佔用大概3G左右(設定成2G時會導致Java Heap OOM)。雖然個人覺得佔用不算多,但是顯然這樣的結果想要試圖去說服一些對記憶體佔用非常挑剔的C++程式設計師們理由還是不夠,於是便通過一定的方式對記憶體的佔用進行了分析,刨根問底。

分析後的記憶體佔用

分析後的記憶體佔用峰值,即在我們的報表資料dump之前,就是屬於記憶體佔用的峰值。由於報表物件佔用的資料非常大,大概1G左右,而且Map的輸出中介結果Value格式是BytesWritable,是通過Java序列化方式dump出來的,因此當時的byte[]非常大(甚至可能超出1G)。於是,便採用了拆分報表輸出的方式,這樣便可以節省一定的記憶體空間。 在分析記憶體的佔用過程中,儘量查詢一些不太合理的記憶體佔用,於是我們便查詢到其中的一個類,在初始化後,佔用500M的記憶體,這就是其中使用到的org.apache.hadoop.fs.FSDataInputStream,為什麼這個類的物件會佔用500M記憶體? 程式碼中初始化org.apache.hadoop.fs.FSDataInputStream後,就立刻佔用500M的記憶體,那麼是否這個類我們使用的方式不對?經過我們單獨寫了一個應用程式的測試(讀取的HDFS與上面的環境一致),其記憶體佔用並沒有達到哪怕是1M。 org.apache.hadoop.fs.FSDataInputStream接收一個InputStream引數,經過列印其具體實現型別,發現為:org.apache.hadoop.hdfs.DFSInputStream,初始化這個類時,記憶體佔用就已經上去了。 於是在MemoryCounter中加入日誌,將物件size大於100M的物件打印出來,發現有一個byte[]長度為536870912佔用記憶體!
Exceed 100M object[Array]:
byte Exceed 100M object[Array]:
[B Array length: 536870912
  初步計算了一下byte[]長度為536870912,估計為2的29次冪,根據條件列印計算出來的結果,發現:
Start estimate: org.apache.hadoop.mapred.MapTask$MapOutputBuffer: 
Start estimate: org.apache.hadoop.util.QuickSort: 
Start estimate: [B: 
Start estimate: [B: 
Exceed 100M object[Array]: [B
於是恍然大悟,是MapOutputBuffer,然後查看了任務配置的引數,果然
mapreduce.task.io.sort.mb=512
  緩衝區設定佔用了512M,也就是2的29次冪,這是需要佔用Map端的Java Heap記憶體,下面就是對這部分的一個學習和回顧。

Map Collect 過程分析

待每次map函式處理完一對key/value,併產生新的key/value後,就會呼叫OutputCollector.collect函式輸出結果,函式內部首先會呼叫Partitioner.getPartition()獲取紀錄的分割槽號,將<key, value, partition>傳遞給MapOutputBuffer.collect函式作進一步的處理。 MapOutputBuffer內部使用了一個緩衝區暫時儲存使用者輸出資料,當緩衝區的資料達到一定閾值的時候,再將緩衝區的資料寫到磁碟上。緩衝區採用的是環形記憶體緩衝區儲存資料(大小為mapreduce.task.io.sort.mb),當達到一定數值(mapreduce.map.sort.spill.percent)後,由執行緒SpillThread將資料寫到一個臨時檔案中,當所有的資料都處理完成後,對所有的臨時檔案進行一次合併生成一個最終檔案。環形緩衝區使得Map Task的Collect階段和Spill階段可以並行地進行。 MapOutputBuffer採用了兩級索引結構,涉及到3個環形記憶體緩衝區,三個緩衝區佔用記憶體的總空間為mapreduce.task.io.sort.mb。

 
  1. kvoffsets, 偏移量索引陣列,用於儲存key/value資訊在位置索引kvindices中的偏移量,一對key/value需要佔用kvoffsets的1個int大小,陣列kvindices的3個int大小
  2. kvindices, 位置索引陣列,用於儲存key/value值在資料緩衝區kvbuffer中的起始位置
  3. kvbuffer,資料緩衝區,用於儲存實際的key/value值,預設情況下可以最多使用整個緩衝區的95%
以上幾個緩衝區讀寫均採用了典型的生產者消費者模型,MapOutputBuffer的collect方法和MapOutputBuffer的write方法是生產者,spillThread執行緒是消費者,通過可重入互斥鎖的條件變數來完成的。 Spill過程是由SpillThread執行緒完成的,SpillThread執行緒實際上是緩衝區kvbuffer的消費者,呼叫sortAndSpill方法將環形緩衝區kvbuffer中的資料寫到磁碟上,函式的工作原理如下:
  1. 利用快速排序演算法對緩衝區kvbuffer的資料進行排序,先按照partition進行排序,然後按照key進行排序。經過排序後,資料以分割槽為單位聚集在一起,同一分割槽內的所有資料按照key有序;
  2. 按照分割槽編號由小到大依次將每個分割槽中的資料寫入任務工作目錄下的臨時檔案output/spillN.out(N為spill的次數),如果使用者設定了Combiner,寫入檔案之前可能會對每個分割槽的資料進行一次資料聚集操作;
  3. 將分割槽資料的元資訊寫到記憶體索引資料結構SpillRecord中,每個分割槽的元資訊包括在臨時檔案的偏移量,壓縮前資料大小和壓縮後資料大小,如果記憶體中的索引大小超過1M,將記憶體索引寫到索引檔案中output/spillN.out.index中。
當所有資料處理完成之後,Map Task會將所有的臨時檔案合併成一個大的檔案,儲存到output/file.out.index中。在進行檔案合併的過程中,以分割槽為單位,對於某個分割槽,採用多輪遞迴合併的方式:每輪合併io.sort.factor個檔案,並將產生的檔案重新加入待合併列表中,重複以上過程以最終得到一個大檔案。

相關推薦

專案Map記憶體佔用分析

最近在專案中開展重構活動,對Map端記憶體儘量要省一些,當前的系統中Map端記憶體最高佔用大概3G左右(設定成2G時會導致Java Heap OOM)。雖然個人覺得佔用不算多,但是顯然這樣的結果想要試圖去說服一些對記憶體佔用非常挑剔的C++程式設計師們理由還是不夠,於是便通過一定的方式對記憶體的佔用進行了

MapReduce的原始碼分析map輸出的原始碼分析

分割槽: 只有一個reduce的情況下,partition號為0 分割槽大有1的情況下,採用hash的方法: 在輸入階段最核心的類是linerecorderReader() 在輸出階段最核心的類是mapoutputbuffer()   達到80%的

unity優化《二》--Texture圖片空間和記憶體佔用分析

打包多種型別的專案,空專案和10張放在Resources資料夾中的圖為比較案例。以下是比較資料。 IPHONE: 1.空專案----空間佔用量42.3MB----IPA大小10MB 2.10張1200*520無壓縮Texure 單張圖佔用量2.8MB----空間佔用量70.2MB

電商專案客戶歷史紀錄

1.點進商品訪問的servlet package com.itheima.web.servlet; import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import ja

在Java Web專案引入Mondrian多維分析框架

本文完全轉載自:http://www.linuxidc.com/Linux/2014-09/107008.htm 我也是初學,為了方便以後檢視,所以轉到自己部落格上了。 -------------------------------------------------------------

MapReduce計算Wordcountmap及reduce的設定

map端的設定:  package wordcount; import java.io.IOException; import java.util.StringTokenizer; import org.apache.hadoop.io.IntWritable; import or

Lua資料結構和記憶體佔用分析

  String又細分為短字串LUA_TSHRSTR和長字串LUA_TLNGSTR兩種,預設長度小於40的為LUA_TSHRSTR,使用全域性stringtable進行管理。即所有短字串都在stringtable中存放,相同字串只會有一份實際資料拷貝,每份相同的TString物件只是存放一個hash值,用來索

Unity3D–Texture圖片空間和記憶體佔用分析

Texture圖片空間和記憶體佔用分析。由於U3D並沒有很好的詮釋對於圖片的處理方式,所以很多人一直對於圖集的大小和記憶體的佔用情況都不瞭解。在此對於U3D的圖片問題做一個實際資料的分析。此前的專案都會存在這樣或者那樣的打包後包大小與記憶體佔用情況的問題,所以這次所以徹徹底底得分析下U3D對於Texture

Linuxbuff/cache記憶體佔用過高解決辦法

如何回收cache? Linux核心會在記憶體將要耗盡的時候,觸發記憶體回收的工作,以便釋放出記憶體給急需記憶體的程序使用。一般情況下,這個操作中主要的記憶體釋放都來自於對buffer/cache的釋放。尤其是被使用更多的cache空間。既然它主要用來做快

spark效能調優(三)shuffle的map記憶體緩衝reduce記憶體佔比

效能優化 shuffle spark.shuffle.file.buffer,預設32k spark.shuffle.memoryFraction,0.2 map端記憶體緩衝,reduce端記憶體佔比;很多資料、網上視訊,都會說,這兩個引數, 是調節shuff

Spark---Shuffle調優之調節map記憶體緩衝與reduce記憶體佔比

1、map端記憶體緩衝,reduce端記憶體佔比概述 map端記憶體緩衝,reduce端記憶體佔比;很多資料、網上視訊,都會說,這兩個引數,是調節shuffle效能的不二選擇,很有效果的樣子,實際上,

JAVA_WEB專案響應獲取檔案路徑的方式(tomcat伺服器)

Web專案中響應端獲取檔案路徑的方式(tomcat伺服器): 比如我在這個Web專案下有放置了這些檔案,需要獲取它們的路徑 1.放置在Web專案下的src目錄中的 d.txt 檔案路徑獲取: ServletContext con = this.

在***專案,手機使用賬戶A登入進入app,檢視模組B的內容XX,顯示正常,檢視模組C的內容XXX也顯示正常,然後進入模組D事件辦理,獲取事件列表,正常,但是選擇辦理的時候,呼叫介面E,一直提

最終解決方案: 經過排查,發現問題是,呼叫獲取事件列表介面,有個欄位為圖片,返回的為空字串,手機端未做判斷,強行載入圖片,導致PHPSESSID發生變化,服務端主動清空cookie,使用者資訊失效,TOKEN驗證失敗,解決辦法,手機端判斷,圖片欄位如果為空,則不載入。 解決

STL的list/set/map等容器clear之後的記憶體佔用

最近在知乎上看到一個問題: 為什麼呼叫 std::map::clear() 後記憶體佔用率沒有降低? size很大的一個map,用完後呼叫了clear()函式,按說記憶體使用率應該能降低很多,top命令觀察,結果是記憶體使用率沒有降低,為什麼呢? 求解答,謝謝。

java 幾種map的儲存原理和記憶體佔用情況

Map,即對映,也稱為 鍵值對,有一個 Key, 一個 Value 。 比如 Groovy 語言中,  def  map = ['name' : 'liudehua', 'age' : 50 ] ,則 map[ 'name' ]  的值是 'liudehua'。  那

關於Android圖片大小、記憶體佔用與drawable資料夾關係的研究與分析

研究內容研究方法測試環境研究過程結果分析結論 研究內容 本篇內容主要探討以下場景:同一張圖片,放置在不同的drawable資料夾,在同一裝置上執行,對圖片大小及記憶體佔用有什麼影響。 研究方法 控制變數法分析法 測試環境 採用錘子T1手機(1080*

vue專案禁止移動雙擊放大,雙手拉大放大的方法

在vue打包後生成的dist目錄檔案下下面有index.html 開啟裡面 把原來的這個 <meta name=viewport content="width=device-width,initial-scale=1">    替換成這個就行了 <meta cont

對某專案Vuex用法的分析

上週五剛釋出一個線上版本,趁著新的需求和bug還沒到來,決定分析一下正在維護的一個使用Vue 2.0 開發的後臺管理系統中Vuex部分程式碼。這部分程式碼不是我寫的,加上我一直在“使用”現成的而不是“搭建”專案,所以這是一個很好的提升。 使用npm安裝vuex,在src檔案下建立store資料夾,如下:

(策略模式+工廠模式+map)套餐 Kill 專案的switch case

接手新任務:接入第三家存證機構,看之前的程式碼使用了swith case判斷使用哪家存證機構,每家存證機構的實現邏輯不一樣 程式碼的壞味道:多層swich case。多層swich case不好維護,是時候應該重構了, 優化前的程式碼 為了便於理解,舉個沒有業務邏輯的例子,基於這個例子上進行優化

在vue專案實現註冊時改變頭像,同時實現將圖片上傳的伺服器

 一.如何實現在註冊時點選頭像時實現更改圖片的操作      1.將img和input[type="file"]放在同一個div中,利用絕對定位,讓兩者擁有相同的大小,將input的預設樣式變為透明,讓img覆蓋的input之上;img中有一個屬性,acc