摘要:進程運行中沒被回收肯定屬于內存泄漏關于這個定義引起討論是在進程退出或崩潰后的情況。關于異步處理問題不適合處理復雜的狀態機解決方案是使用隊列結構進行可控的異步并發。
front to back
業務上 : front 面向展示 交互 ; back 功能 服務 數據一致性等等
環境 : front browser webview 單機; back 集群 高并發
思想差異 : front 快速開發 快速渲染 視覺效果 等等 ; back 服務穩定,性能,內存泄漏等等
V8 內存的簡介首先通過memoryUsage可以查看node進程的使用情況,具體介紹如下
process.memoryUsage(); 查看node進程內存使用情況 單位是字節 { rss: 20725760, (resident set size)進程的常駐內存 heapTotal: 7376896, 已申請到的堆內存 heapUsed: 3881280, 當前使用的堆內存 external: 8772 , c++的內存使用,受v8管理 }
針對上面api使用寫了個相關例子
let showMem=function () { var mem=process.memoryUsage(); var format=function (bytes) { return (bytes/1024/1024).toFixed(2)+"MB"; } console.log("Process :heapTotal "+format(mem.heapTotal)+" heapUsed "+ format(mem.heapUsed)+" rss "+format(mem.rss)); console.log("------------------------------------") } var useMem=function () { var size=200*1024*1024; //每次構建200MB對象 var buffer=new Buffer(size); for(var i=0;iheapTotal和heapUsed變化極小,唯一變化rss值,且該值遠超V8內存分配限制(說明:V8的內存限制:64位系統約為1.4GB、32位系統約為0.7GB (這個規定是node源碼 中限制的),具體測試可以將上述實例中buffer改成array即可)
說明:node 內存由通過v8進行分配的部分(新生到和老生代)(只有這部分才會受v8垃圾回收的限制)和node進行自行分配的部分(例如buffer)
額外補充
--max-old-space-size 命令就是設置老生代內存空間的最大值
--max-new-space-size 命令則可以設置新生代內存空間的大小
這兩個參數只能在node啟動時進行設置
下面從gc層面談論下v8內存,這個可以說很多,我的云筆記中關于java和js的內存使用,分配,gc等整理了好幾個系列,下面我用自己的話簡單總結下。
關于內存分區有以下兩個大類:
new space(特征:對象存活時間短) 又分為from和to兩個區域,采用復制算法,空間換時間。如果存活多次,轉移到老生代中。
老生代中(對象存活時間長),采用mark-sweep(標記清除)和mark-compact(標記整理),缺點容易形成內存碎片,導致無法分配大對象。v8主要使用mark-sweep,在內存空間不夠時,才使用標記整理。老生代又可以細分Old Space(新生代中gc活過2次晉升到這個空間)、Large Object Space(大對象,一般指超過1MB,初始時直接分配到此),Map Space(“隱藏類”的指針,便于快速訪問對象成員)、Code Space(機器碼,存儲在可執行內存中)
關于gc,總的來說在js中不同對象存活時間不同,沒有一種算法適應所有場景,內存垃圾進行分代,針對不同分代使用相應高效算法,有些gc算法和java是一樣的,復制(空間換時間,new Space),標記清除和標記整理(old space)等等。
補充存活標記依據
全局變量或者有由全局變量出發,可以訪問到的對象
正在執行的函數中的局部對象,包括這些局部對象可以訪問到的對象。
閉包中引用的對象
關于內存,偏底層語言(例如c)和js以及java不一樣
#c代碼 #includevoid init() { int arr[5]={}; for(int i=0;i<5;i++){ arr[i]=i; } } void test(){ int arr[5]; for(int i =0;i<5;i++){ printf("%d ",arr[i]); } } int main(int argc,char const *argv[]){ init(); test(); return 0; } // 0 1 2 3 4 # java代碼 public class Test { public static void main(String[] args){ init(); test(); } public static void init(){ int[] arr=new int[]{0,1,2,3,4}; // for(int i=0;i<5;i++){ // System.out.println(arr[i]); // } } public static void test(){ int[] arr=new int[5]; for(int i=0;i<5;i++){ System.out.println(arr[i]); } } } // 0 0 0 0 0 上述例子說明c語言堆棧執行過程中,函數執行完堆棧釋放,程序員如果不關注釋放過程,出現一些問題 ,
內存泄漏
而js和java就不會,因為內存自動分配,垃圾自動回收,不用考慮臟數據擦除。首先什么是內存泄漏?
對象不再被應用程序使用,但是垃圾回收器卻不能移除它們,因為它們正在被引用。
node進程運行中garbage沒被回收肯定屬于內存泄漏,關于這個定義引起討論是在node進程退出或崩潰后的情況。我的理解是如果有部分內存比如共享內存(用于進程間通信),如果沒被釋放,這依然屬于內存泄漏,內存泄漏不僅僅只進程層面。
內存泄漏原因有好幾種,ppt有的,我不在列舉,我在分享過程中有同學提出個疑問,關于exports使用中為什么會導致泄漏,印象比較深刻,可能當時講的不清楚,下面寫個具體例子詳細闡述下。
//A.js var leakAry=[]; exports.leak=function(){ leakAry.push("leak "+" gcy "+new Date()); } //B.js var obj=require("./a"); for(var i=0;i<10;i++){ obj.leak(); }在node當中,為了加速module訪問,所有module都會被編譯緩存,上述代碼導致泄漏的原因就是模塊上,被緩存局部變量重復訪問,因為沒初始化,導致內存占用不斷增大。
其次平時如何定位內存泄漏具體問題。
var http=require("http"); var heapdum=require("heapdump"); var leakArray=[]; var leak=function () { for(var i=0;i<100000;i++){ leakArray.push("leak "+Math.random()); } }; var i=0; http.createServer(function (req,res) { leak(); //泄漏觸發位置 i++; res.writeHead(200,{"Content-Type":"text/plain"}); res.end("hello world gcy"+i); }).listen(1337); console.log(process.pid); console.log("server start gcy"); ------------------------------------------------------------- for ((i=1;i<=10000;i++)); do curl -v --header "Connection: keep-alive" "http://127.0.0.1:1337/" done 批量100和10000個請求,記錄heap dump鏡像,通過對比視圖查看變化比較大地方,通過分析定位具體泄漏位置,展示效果如下圖可以看到有三處對象明顯增長的地方,string、concatenated string以及 array 對象增長。點擊查看一下對象的引用情況,可以發現原因是leak執行,leakArray沒有初始化,導致其里面字符串沒有被清除,從而導致內存泄漏。
關于異步處理問題:不適合處理復雜的狀態機
解決方案:是使用隊列結構進行可控的異步并發。
關于這一點理解分享中上有人提出可異議,
弱計算
我的理解是比如邏輯中有大量的promise待處理,一旦此邏輯比較多,我們沒法掌控,宏觀上沒法知曉具體執行情況,但是通過隊列,在高并發請求下,大量的狀態機promise通過隊列
的管理,我們可以做到可控,哪些被消費了,狀態機所處某個過程的比例都可以統計,一旦有這些統計信息,我們就可以進行相應的處理。求證。什么是 IO 密集型? 控制器busy
什么是 CPU 密集型? 運算器busy
關于弱計算的分析可以用node生成profile文件,然后通過chrome進行分析或者webstrome自帶的v8 profiling進行分析,可以得到一系列函數執行時間統計和調用堆棧過程時間消耗統計,依據這些信息,我們在做相應的優化。圖中顯示的是例子test2的結果。
部署 child_process//普通情況,只是作為用法示例 var fork=require("child_process").fork; var cpus=require("os").cpus(); for(var i=0;i總結 child_process 模塊給node提供了一下幾個方法創建子進程
1: spwan(); 啟動一個子進程執行命令
2: exec() 啟動一個子進程執行命令,與spwan不同的是,他有一個回調函數獲知子進程狀況
3: fork() 與spwan類似 不同地方在于 在創建子進程的時候只需指定 需要執行的JavaScript文件即可上面方法很少用了,node當中有cluster模塊,簡單的幾個方法就可以創建集群,其本質基于上面的封裝,底層實現原理基于句柄共享。
var index=require("./app"); if (cluster.isMaster) for (var i = 0, n = os.cpus().length; i < n; i += 1) cluster.fork(); else index.app(); ------------------------------------------- //app.js function app() { var server = http.createServer(function(req, res) { res.writeHead(200); res.end("hello world gcy "); console.log(cluster.worker.id); }); server.listen(8088); } exports.app=app;cluster使用中有三個問題
1、round-robin是當前cluster的默認負載均衡處理模式(除了windows平臺),自行設定負載算法
可以在cluster加載之后未調用其它cluster函數之前執行:cluster.schedulingPolicy = cluster.SCHED_NONE。2、進程監控問題
master進程不會自動管理worker進程的生死,如果worker被外界殺掉了,不會自動重啟,
只會給master進程發送‘exit’消息,開發者需要自己做好管理。3、數據共享問題
各個worker進程之間是獨立的,為了讓多個worker進程共享數據(譬如用戶session),
一般的做法是在Node.js之外使用memcached或者redis。cluster適用于在單臺機器上,如果應用的流量巨大,多機器是必然的。這時,反向代理就派上用場了,我們可以用node來寫反向代理的服務(比如用 http-proxy )
,好處是可以保持工程師技術棧的統一,不過生產環境,我們用的更多的還是nginx,部分重要配置如下。nginx做集群
upstream gcy.com{ server 127.0.0.1:3000 weight=1; server 127.0.0.1:3001 weight=2; server 127.0.0.1:3002 weight=6; }維護維護主要做好以下三點
日志
異常處理
第三方依賴管理。
異常處理解釋下,有人提出疑問:異常沒有被捕獲一路冒泡 ,會觸發uncaughtException 事件,
總結
如果異常出現之后,沒有進行正確的恢復操作可能導致內存泄漏,清理已使用的資源
(文件描述符(清除文件的占用)、句柄(Master傳給work的標識)等) 然后 process.exit。qcon現場聽一次,自己分享一次,總結一次,感覺收貨蠻大的,有些地方自己加深了理解,分享中front to back開頭部分,原先8頁太多,本應一筆帶過,講的時候廢話太多,原本我只想闡述其中幾個關鍵名詞。
分享本身是一個學習,開拓眼界的的過程,切身體會,還是需要自己實踐,寫具體case。
上述基本上是我講的過程記錄,做個總結,以便回顧。
演示部分鏈接, demo
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/82870.html
摘要:前戲補上參會的完整記錄,這個問題從一開始我就是準備自問自答的,希望可以通過這種形式把大會的干貨分享給更多人。 showImg(http://7xqy7v.com1.z0.glb.clouddn.com/colorful/blog/feday2.png); 前戲 2016/3/21 補上參會的完整記錄,這個問題從一開始我就是準備自問自答的,希望可以通過這種形式把大會的干貨分享給更多人。 ...
閱讀 1763·2021-09-23 11:34
閱讀 2485·2021-09-22 15:45
閱讀 13011·2021-09-22 15:07
閱讀 2250·2021-09-02 15:40
閱讀 4154·2021-07-29 14:48
閱讀 1087·2019-08-30 15:55
閱讀 3252·2019-08-30 15:55
閱讀 2199·2019-08-30 15:55