一.問題切入
調用spark 程序的時候,在獲取數據庫連接的時候總是報 內存溢出 錯誤
(在ideal上運行的時候設置jvm參數 -Xms512m -Xmx1024m -XX:PermSize=512m -XX:MaxPermSize=1024M,不會報錯)
二.jvm參數 和 saprk 參數 和內存四區 解讀
1.內存四區
1、棧區(stack):由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。
2、堆區(heap:一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回 收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表。
3、數據區:主要包括靜態全局區和常量區,如果要站在彙編角度細分的話還可以分爲很多小的區。
全局區(靜態區)(static):全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的 另一塊區域。 程序結束後有系統釋放
常量區:常量字符串就是放在這裏的。 程序結束後由系統釋放
4、代碼區:存放函數體的二進制代碼。
參考: http://blog.csdn.net/wu5215080/article/details/38899259
2.jvm 參數
-Xms512m -Xmx1024m-XX:PermSize=512m -XX:MaxPermSize=1024M
-Xms JVM初始分配的堆內存 默認是設備物理內存的 1/64
-Xmx JVM最大允許分配的堆內存,按需分配 默認是設備物理內存的 1/4
-XX:PermSize JVM初始分配的非堆內存 默認是設備物理內存的 1/64
-XX:MaxPermSize JVM最大允許分配的非堆內存 默認是設備物理內存的 1/4
參考: http://www.cnblogs.com/mingforyou/archive/2012/03/03/2378143.html
3.spark參數
-- driver-memory : driver運行的內存大小,默認1G driver:sparkcontext ,sqlContext等運行的地方, sparkcontext ,sqlContext 一般運行在棧內存
-- executor-memory : executor的內存大小,默認1G executor: rdd 等運行的地方 ,rdd 一般運行在棧內存
conf spark.storage.memoryFraction=0.3 spark用於緩存rdd的內存百分比(剩下的內存用來保證任務運行時各種其它內存空間的需要),默認0.6(和運行在堆或棧沒有關係)
得出:
棧內存 正比於 driver-memory : 內存被 sparkcontext,sqlContext 等固定佔用,和數據庫連接沒有多大關係
棧內存 正比於 executor-memory ; executor-memory 分兩種: rdd 和其他(包含獲取獲取 數據庫連接的內存)
三.問題分析和解決
方向:增大executor-memory 和減小 conf spark.storage.memoryFraction 的值 ,根據具體環境而定
命令方式:
nohup spark-submit \
--masteryarn \
--executor-memory 1024M \
--confspark.storage.memoryFraction=0.3 \
--classcom.xiaopeng.bi.gamepublish.GamePublishKpi \
/home/hduser/projs/xiaopeng_bi.jar60 >> /home/hduser/projs/logs/gamepublishkpi.log &
代碼方式:
val sparkConf = newSparkConf().setAppName(this.getClass.getName.replace("$",""))
.set("spark.default.parallelism", "60") // 1. 調節並行度
.set("spark.serializer","org.apache.spark.serializer.KryoSerializer") // 3.序列化方式
.set("spark.shuffle.consolidateFiles", "true")// 4. shuffle 過程中 合併小文件
.set("spark.storage.memoryFraction", "0.4");// 5.cache佔用的內存佔比
.set("spark.sql.shuffle.partitions", "60")// 6.shuffle 時 partion的個數