整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          PM技術課|計算機網絡知多少?

          PM技術課|計算機網絡知多少?

          文筆者將與大家分享:TCP/IP協議族、HTTP、TCP、UDP、Socket、狀態碼等的基礎知識。

          一個完整的通信過程

          互聯網,顧名思義,就是互相連接,形成網絡。其中的關鍵是“聯網”,從技術上看,聯網就是通信。

          那么,通信的過程是怎么樣的呢?使用瀏覽器訪問網頁,是最為常見的通信方式,我們也以訪問網頁為例,查看一個完整的通信過程。

          我們在瀏覽器中輸入一個 URL,回車之后便會在瀏覽器中觀察到頁面內容,實際上這個過程經過了很多個步驟。

          1. 我們在地址欄輸入一個URL鏈接,比如www.baidu.com;
          2. 瀏覽器向百度服務器發送了一個訪問請求;
          3. 百度服務器接收到這個訪問請求之后進行處理和解析,知道客戶端是想要訪問網站;
          4. 百度服務器返回對應的響應給瀏覽器,包含了頁面的源代碼等內容;
          5. 瀏覽器再對其進行響應解析;
          6. 瀏覽器將網頁呈現出來。

          互聯網的基礎:TCP/IP協議族

          互聯網的的關鍵是通信,而通信的關鍵則是通信協議。

          說句題外話,有段時間,聯想5G投票事件鬧得沸沸揚揚,除了民族情緒,更多的還是對通信協議的爭奪,誰掌握了通信協議,誰就掌握了通信的核心。

          計算機之間的通信協議是TCP/IP協議族,通信協議定義了通信的基本問題。

          比如:由哪一邊先發起通信、使用哪種語言進行通信、數據傳輸順序是怎么樣的、怎樣結束通信等規則,這些規則稱為協議(protocol)。通過這些協議,不同的計算機、手機甚至智能手表之間都可以互相通信。

          “族”的意思是很多種協議,比如TCP、UDP、IP、FTP、HTTP、ICMP等都屬于 TCP/IP 族內的協議。這些協議本身又可以劃分為不同的層次,大致可以分為4層,分別是:應用層、傳輸層、網絡層和鏈路層。

          當然也有不同的劃分方式,不同的劃分方式大同小異,沒有本質的區別。

          1)應用層

          應用層負責傳送各種最終形態的數據,是直接與用戶打交道的層,典型協議是HTTP、FTP等。

          2)傳輸層

          傳輸層負責傳送文本數據,傳輸層有兩個性質不同的協議,分別是 TCP(Transmission Control Protocol,傳輸控制協議)和 UDP(User Data Protocol,用戶數據報協議)。

          3)網絡層

          網絡層負責分配地址和傳送數據,主要協議是IP協議。

          IP地址(Internet Protocol Address)是指:互聯網協議地址,它為互聯網上的每一個網絡和每一臺主機分配一個邏輯地址,以此來屏蔽物理地址的差異,用來在網絡中標記一臺電腦的一串數字,比如192.168.1.1。

          4)鏈路層

          鏈路層向該層用戶提供透明的和可靠的數據傳送基本服務。

          透明性是指:該層上傳輸的數據的內容、格式及編碼沒有限制,也沒有必要解釋信息結構的意義;可靠的傳輸使用戶免去對丟失信息、干擾信息及順序不正確等的擔心。

          你可能會感到奇怪,為什么要層次化呢?

          1. 在保證層次之間接口不變的情況下,層次內部可以改動,不至于“牽一發而動全身”
          2. 降低了開發的復雜度,開發的過程中,也只需要關注某一層的協議,而不需要深入了解所有的協議。

          數據是如何流動傳輸?

          數據發送的時候依次經過應用層、傳輸層、網絡層、鏈路層,之后通過光纖等硬件傳送給接收端。

          接收端的鏈路層接收到數據,并依次通過網絡層、傳輸層、最終到達應用層,進行數據處理。

          首先,作為發送端的客戶端在應用層(HTTP 協議)發出的 HTTP請求(比如想要訪問http://www.baidu.com),并生成HTTP數據。

          1. 為了傳輸方便,在傳輸層(比如TCP 協議)把從應用層處收到的數據(HTTP 數據)進行封裝,之后轉發給網絡層。
          2. 在網絡層(IP 協議),增加作為通信目的地的地址后轉發給鏈路層。
          • 給這些數據附加上以太網數據并進行發送處理,生成的以太網數據將通過物理層傳輸給接收端。
          • 接收端在鏈路層接收到數據,依次往上層傳輸,直至應用層。當傳輸到應用層,才能算真正接收到由客戶端發送過來的 HTTP 請求。

          HTTP是啥?

          HTTP協議是Hyper Text Transfer Protocol(超文本傳輸協議)是用于服務器傳輸超文本到本地瀏覽器的傳送協議。HTTP是TCP/IP協議族的一部分,屬于應用層的面向對象的協議,由于其簡捷、快速的方式,受到了廣泛的應用。

          HTTP協議工作于客戶端-服務端架構上,客戶端向服務器發送所有請求,服務器根據接收到的請求后,向客戶端發送響應信息。

          HTTP協議具有以下特點:

          1. HTTP協議簡單快速,客戶端向服務器請求服務時,只需傳送請求方法和路徑。由于HTTP協議簡單,使得HTTP服務器的程序規模小,因而通信速度很快。
          2. HTTP系統通信靈活,允許傳輸任意類型的數據對象。比如:文字、圖片、音頻和視頻等內容,這也是我們可以在瀏覽器或者手機APP查看各種音頻、視頻的原因。
          3. HTTP協議面向無連接通信,面向無連接是指通信雙方不需要事先建立一條通信線路,而是把每個帶有目的地址的包送到線路上,由系統自主選定路線進行傳輸。這就像我們做出租車的時候,只會告訴司機目的地,并不需要跟司機說走哪條路。

          TCP、UDP、Socket

          TCP

          TCP(transport control protocol,傳輸控制協議)是面向連接的、可靠的流協議。

          流就是指不間斷的數據,你可以把它想象成排水管中的水流。

          面向連接,是指發送數據之前必須在兩端建立連接。建立連接,為數據的可靠傳輸打下了基礎。

          可靠的意思是信息不會丟失,當一臺計算機想要與另一臺計算機通訊時,兩臺計算機之間的通信需要暢通且可靠,這樣才能保證正確收發數據。比如:查收電子郵件的時候,有時候差一個字,意思可能就不一樣了,所以要保證每一個字都能夠接收到。

          在技術實現上,TCP為了保證報文傳輸的可靠,就給每個包一個序號,序號也保證了傳送到接收端實體的包的按序接收。接收端接受到數據之后,也會向發送端發送一個確認的信息(Acknowledgement ,ACK)。如果發送端在一定時間內沒有收到接收端返回的ACK,那么發送端會重新發送數據,保證通信的可靠性。

          UDP

          UDP(user datagram protocol,用戶數據報協議)與TCP協議一樣用于處理數據包,是一種無連接,面向消息的,提供高效率服務的協議。

          UDP是面向無連接的協議, UDP不需要在發送數據前進行建立連接,想發數據就可以開始發送了。有時候,接收端還沒有準備好,發送端就開始發送數據了!

          UDP也沒有數據拆分和編號操作,一股腦直接發送過去了。特別是在網絡傳輸狀況較差的時候,發送端只顧著發送數據,接收端可能壓根沒有接受到數據。

          但UDP這樣做也有好處,就是傳輸速度快,TCP在傳輸之前要建立連接,傳輸過程中還要編號。接收端接收到所有編號之后,重新組裝成信息,需要花費不少時間,在對時間較高的場景,這樣做明顯會帶來較長的時延。

          所以,UDP常用在對實時性較高的通信領域,比如:視頻會議,這些情況對實時性要求較高,即使丟失了一些數據,也不影響接受信息。

          TCP提供面向連接的可靠服務 ,UDP提供無連接的不可靠的服務。對數據準確性要求高,速度可以相對較慢的,可以選用TCP,對實時性要求高的場景可以使用UDP。

          Socket

          除了TCP/IP,我們可能也會聽說過Socket。

          Socket(套接字) 是對 TCP/IP 協議的封裝,Socket 只是個接口(API)不是協議,通過 Socket 我們才能使用 TCP/IP 協議。

          創建 Socket 接口的時候,需要指定傳輸層協議,可以是 TCP 或者 UDP,當用 TCP 連接,該Socket就是個TCP連接,反之亦然。

          狀態碼:404

          服務器響應客戶端請求的時候,會返回HTTP狀態碼(HTTP Status Code)。狀態碼是表示服務器響應狀態的3位數字代碼,表示訪問請求已經被服務器接收、理解并接收。

          狀態碼可以分為下面5類:

          1. 1xx:指示信息–表示請求已接收,繼續處理;
          2. 2xx:成功–表示請求已被成功接收、理解、接受;
          3. 3xx:重定向–要完成請求必須進行更進一步的操作;
          4. 4xx:客戶端錯誤–請求有語法錯誤或請求無法實現;
          5. 5xx:服務器端錯誤–服務器未能實現合法的請求。

          下面是幾個比較常見的狀態碼。

          1)200:OK

          請求已成功,出現此狀態碼是表示正常狀態。

          2)403:Forbidden

          服務器已經理解請求,但是拒絕執行它,通常是服務器文件權限設置導致,比如:用戶無權訪問。

          3)404:Not Found

          用戶最常見的狀態碼是404,即請求失敗,通常是訪問的資源在服務器中不存在。用戶沒有找到自己需要的資源,給用戶的體驗很不好,自定義404錯誤頁面是提高用戶體驗的常見做法。

          當用戶訪問的資源不存的時候,不是直接返回404,而是指向一個設計好的html 文件,有些網站甚至會為404設置個小游戲,作為彩蛋。

          比如:游戲公司暴雪的404網頁延續了其冷酷的設計,一張被錘子砸得面目全非的網頁告訴用戶:你真的走錯路了。

          八卦:下載那些事兒

          帶寬與網速

          我們去中國電信、中國聯通、中國移動辦理寬帶網絡的時候,帶寬通常是10M、20M,但安裝完成后,下載速度卻可能只有1M/s,遠遠達不到所說的10M。是運營商欺騙了我們么?帶寬、網速是什么,又有什么關系呢?

          • 帶寬是數據傳輸的速度,單位是比特/秒(bps),10M=10Mbps。
          • 網速是數據傳輸的速度,但是單位與帶寬的單位不同,單位是字節/秒(B/s),1MB/s=1024KB/s 。

          比特是信息的最小單位,1字節=8比特,1字節/秒=8比特/秒。因此, 10M帶寬=1.25MB/s網速,1M帶寬=0.125MB/s=128KB/s,運營商提供的10M網絡,轉換成網速也就是1.25M/s,跟我們日常的體驗相符,這也算是運營商的“小詭計”了。

          帶寬成本

          對普通用戶而言,10M的寬帶,每個月的上網費用就要幾十塊錢。不只是對普通用戶,帶寬成本對互聯網公司而言同樣是巨大的成本,特別是對于各大視頻網站而言,帶寬成本是非常巨大的運營成本。

          根據阿里云提供的數據,按流量計費,要0.8元/G,一部電影通常在2G左右,下載一部電影就需要 1.6元,這個數據看起來可能不大,但考慮到用戶規模,數據就會變得很大了。如果有100萬個用戶,每個用戶每天看一部電影,每天的帶寬成本可能就有160萬元,這也是視頻網站難以盈利的重要原因。

          為了減低帶寬成本,互聯網公司也是想盡辦法,比如:百度網盤會對非會員限速,巨大的帶寬成本是百度網盤這么做的重要原因。

          面對用戶對限速的質疑,百度網盤回應,“作為一款免費的云存儲產品,每年的服務器成本和帶寬成本是硬傷啊。百度網盤存活著為廣大用戶提供免費的空間內存已經是一筆需每年持續支出的高額成本。除此之外,還有服務成本和帶寬成本,寶寶們雖然已經為家里的網絡網速買過單,但是當寶寶們打開百度網盤上傳和下載文件時,我們還需要為這些文件傳輸時的帶寬進行支付,用戶文件傳輸時帶寬越大我們需要支付的費用越高”。

          即使是財大氣粗的百度公司,也要考慮到昂貴的帶寬成本,帶寬成本始終是高流量網站需要面對的問題。

          P2P

          提高下載速度就要增加帶寬,增加帶寬,運營成本也隨之提高;如果不增加帶寬,下載速度就會降低,用戶體驗很差。

          有沒有什么辦法可以解決成本和下載速度之間的矛盾呢?

          P2P是個好主意,這里的P2P不是互聯網金融的P2P,而是點對點(peer to peer)通信的網絡技術。P2P依賴網絡中參與者的計算能力和帶寬,而不是把依賴都聚集在較少的幾臺服務器上,互聯網金融的P2P借鑒了這個技術概念。

          定義有些拗口,我們舉個例子就明白了。

          傳統下載方式是從服務器端下載文件到客戶端,由于是從一臺服務器下載,服務器所提供的帶寬是一定的,因此下載人越多速度越慢。假設服務器的帶寬是100M,即12500kb/s。有100臺客戶端連接,那么每一臺的帶寬就是125kb/s,難怪下載速度這么慢!

          為了避免服務端帶寬的限制, P2P下載應運而生。與傳統下載不同,P2P下載是用戶越多,下載越快,這是因為P2P用的是一種共享的方式提供下載。

          我們可能也會聽說過BT,BT全名叫”BitTorrent”, BT和P2P有些差別,P2P指的是數據的一種傳送方式,而BT是應用這種方式的軟件。但我們大多數人接觸較多的都是P2P,這里就用P2P直接使用P2P代指P2P和BT了,請讀者知曉。

          我們以迅雷下載為例,說明P2P的下載過程。

          通過P2P下載,在不增加服務器帶寬的時候,卻能提高下載速度!網絡真奇妙!

          本文由@李艷賓 原創發布于人人都是產品經理,未經許可,禁止轉載

          題圖來自Unsplash, 基于CC0協議

          車儀表盤指示燈亮或閃速,這是在提醒駕駛人員你的汽車存在某種故障,每次啟動汽車前大家一定要注意檢查一下自己的儀表盤。儀表盤的指示燈太多,可能很多車主都不了解每個指示燈代表的意思。小編曾經有給大家介紹過汽車儀表盤指示燈圖解,如下小編將馬上為大家收集汽車故障燈標志圖解、汽車故障燈大全。請各位車主對號入座。

          汽車故障燈標志圖解

          自動變速器報警信號燈、未嚙含”PARK“、自適應前照燈系統故障

          自適應前照燈系統關閉、系統信息指示燈、防盜啟動鎖止系統指示燈

          定速巡航控制指示燈、智能卡式遙控鑰匙系、定速巡航主指示燈

          智能鑰匙系統警告燈、巡航設置指示燈、牽引力關閉指示燈

          燃油經濟性指示燈、AFS(自適應前照燈)、電子駐車制動系統警告

          踩制動/離合踏板指示燈、點火警告燈、sos呼叫警告燈

          汽車需要維修警告燈、換擋杠不可設置P檔指示燈、換擋杠不可設置P檔指示燈

          電子方向盤鎖止警告燈、空調濾清器故障燈、燈泡損壞故障燈

          燈泡損壞故障燈、燈泡損壞故障燈、燈泡損壞故障燈

          燈泡損壞故障燈、服務期限指示燈、服務有效指示燈

          發動機轉速低指示燈、發動機轉速高指示燈、自適應彎道燈故障指示燈

          巡航控制指示燈、車輛維修警示燈、超聲波倒車輔助指示燈

          盲區監測指示燈、傳動系統警告燈、前向碰撞預警提示燈

          車道保持指示燈、升檔提示燈、燃油表/加油口蓋位置

          電子節氣門控制指示燈、變速箱過熱警告燈、DBC下坡制動控制

          ABC主動車身控制、空氣濾清器更換警告燈、掛車接合器故障燈

          車身太低警告燈、車輛正被升起指示燈、燃油濾清器警告燈

          車鑰匙指示燈、車門未關閉警告燈、無法檢測到鑰匙指示燈

          冷卻液液位過低警告燈、夜市功能指示燈、夜市功能指示燈

          胎壓指示燈、燃油不足警告燈、動力蓄電池故障指示燈

          運動模式指示燈、車距警告燈、遙控器電量低警告燈

          遙控器警告燈、發動機動力部分損失、發動機排放系統警告燈

          剎車溫度過高警告燈、HDC坡道車速控制、車外溫度指示燈

          車窗防夾功能指示燈、無窗防夾功能指示燈、自適應大燈系統故障燈

          自動手剎指示燈、安全帶/安全氣囊警告燈、發動機艙蓋打開指示燈

          剎車片磨損指示燈、轉向阻力系統故障燈、水溫報警指示燈

          發動機預熱指示燈、駐車制動與制動油位、發動機防盜鎖止系統

          乘客側氣囊指示燈、前排安全帶指示燈、電子轉向系統警告燈

          轉向系統警告燈、乘客側氣囊指示燈、VSA(車輛穩定控制)

          VSA車輛穩定控制、發動機電子防盜指示燈、燃油液位低警告燈

          保持模式指示燈、燈泡損壞指示燈、巡航控制指示燈

          前霧燈指示燈、前照明指示燈、遠光燈指示燈

          后霧燈指示燈、換擋指示燈、行李箱蓋未關閉指示燈

          車門未關閉指示燈、后窗加熱指示燈、EBD電子制動力分

          駐車輔助指示燈、智能進入和啟動系統、超速檔關閉指示燈

          坡道起步輔助警告燈、霜凍警示燈、霜凍警示燈

          胎壓低警告燈、信息指示燈、轉向指示燈

          可調空氣懸架指示燈、可調空氣懸架指示燈、清洗液液位低故障燈

          清洗液液位低故障燈、光線/雨量傳感器故障燈、鑰匙不在車內提示燈

          燈泡損壞指示燈、自動變速箱油溫警告燈、鑰匙在車外警告燈

          動力轉向警告燈、安全指示燈、VSC車輛穩定控制

          低水溫指示燈、防滑指示燈、VDC車身動態穩定

          乘客安全帶提示燈、制動系統警告燈、ESP車身穩定控制

          EPS電子轉向助力、轉向鎖止系統故障燈、發動機啟動系統故障燈

          發動機機油量警告燈、低壓輪胎位置指示燈、手動變速器換擋指示燈

          燃油濾清器警告燈、TCS牽引力控制系統、TCS牽引力控制系統

          輪胎壓力監測指示燈、柴油顆粒濾清器指示燈、轉速限制功能指示燈

          發動機機油有位指示燈、機油感應器指示燈、車窗雨刮器指示燈

          減震器調節指示燈、拖車牽引裝置指示燈、拖車轉向燈指示燈

          鑰匙未在車內指示燈、鑰匙未被識別指示燈、車道保持輔助系統指示燈

          駕駛員疲勞提示指示燈、限速警告指示燈、遙控鑰匙電量低指示燈

          下坡行駛輔助指示燈、發動機關閉指示燈、發動機未被關閉指示燈

          制動踏板未踩下指示燈、車輛保養提示燈、ABC主動車身控制

          DTC和DSC指示燈、四驅系統警告燈、啟動機系統指示燈

          節能駕駛輔助指示燈、系統故障警告燈、動力電池過熱警告燈

          動力模式指示燈、EV驅動模式指示燈原文地址:http://www.pikacn.com/news/20161/3878.html

          動力電池故障警告燈、動力蓄電池電量不足、電機及控制器過熱指示燈

          充電線鏈接指示燈、運行準備就緒指示燈、環保駕駛模式指示燈

          發動機故障燈/尾氣排放故障燈、EPC發動機功率控制、發動機系統故障指示燈

          安全氣囊警告燈、安全氣囊警告燈、ABS防抱死系統指示燈

          點火警告燈、點火警告燈、機油壓力警告燈

          車身穩定控制系統關閉、車身穩定控制系統指示燈、機油油位過低警告燈

          安全帶指示燈、燃油液位低警告燈、制動系統警告燈

          期需要對公司的接口做線上的巡查監控,需要寫一個腳本放到服務器上,定時運行腳本監測線上接口是否正常。

          測試的接口不是HTTP協議,而是公司基于TCP協議開發的私有協議,因此不能直接用現成的一些接口測試工具,需要自己寫代碼來調用接口

          由于是私有協議,為了方便各業務項目進行通信,開發部門統一提供了一個TClient的jar包,底層使用了netty框架進行通信。調用方只需要按照協議的格式組裝二進制的包,然后直接調用TClient的sendMessage方法就可以把數據發送出去,服務端處理完成后會異步回調,將響應數據返回給客戶端。

          腳本寫完了,偽代碼如下

          public class Demo{

          public void invoke(){

          // 創建TClient并初始化

          TClient client=new TClient(xxx);

          // 組裝接口數據包

          Data data=new Data(xxx);

          // 發送數據

          Response res=client.sendMessage(data);

          // 檢查結果、存儲結果、發送郵件

          doSomething();

          // 關閉client

          client.close();

          }

          }

          測試腳本中,每隔一分鐘,創建一個Demo對象,調用invoke方法

          Demo demo=new Demo();

          demo.invoke();

          腳本寫好后在服務器上調試了下,接口返回數據正常,于是正式啟動定時任務,觀察了一會,運行一切正常,Perfect!

          第二天早上到公司,登上服務器,查看昨晚腳本的運行情況,看了下日志。

          打開日志我就震驚了,What?OutOfMemoryError!竟然內存泄漏了!

          平常都是開發寫bug時出現內存泄漏,今天終于輪到我自己了!


          最后一條日志顯示為下午17:17左右,也就是腳本大概運行了4小時后出現了內存泄漏。查看了下腳本進程,果然已經崩潰了,并且生成了一個dump文件。


          經常做性能測試的同學,對內存泄漏都不陌生。內存泄漏總結來說就是JVM中存儲的對象太多了,占滿了全部內存空間,并且這些對象都是不可回收的。這樣程序就不能再繼續運行了,因為已經沒有空間了。

          舉個例子,就好像去飯館吃飯,飯館里總是不斷的有人進去,也有人出來。如果某天來了一幫人占滿了飯店,并且賴著不走了,這樣新顧客就進不來了,這個時候估計老板就崩潰了。

          我先review了腳本的代碼,沒發現什么異常的問題。有的朋友可能會說,你不是每個1分鐘創建一個Demo對象嗎,運行這么長時間,會不會是Demo對象太多了?

          其實并不會,寫腳本的時候也考慮過這個問題,每次new Demo對象,因為上一次腳本已經執行完了,那么上一次的Demo對象就沒有引用了,這樣JVM在垃圾回收的時候會把上一次的Demo對象清理掉。這樣并不會造成內存泄漏。

          目光再回到服務器上,Java進程在崩潰時,自動生成了一個堆dump文件,如果已經發生了內存泄漏,可以分析這個dump文件,看看里面那些對象比較多,這樣就能確定原因了。

          一般在工作中分析內存泄漏時,可以把dump文件下載到本地,然后通過jvisualvm或者jprofiler打開文件,工具自動會分析哪些對象數量最多。

          但是這個文件有1.3G,公司服務器下載有限速,想下載下來估計得等到7月7號testfan性能測試實戰班開課那天了。

          突然想到另外一個分析內存泄漏的工具MAT,之前都是在windows下使用MAT,其實MAT也有Linux版本,可以直接在服務器上對dump文件進行分析。

          簡單介紹下工具的使用方法:

          1、 登錄官網,下載Linux x86_64/GTK+版本

          https://www.eclipse.org/mat/downloads.php

          2、 解壓后修改MemoryAnalyzer.ini配置文件,配置jvm參數(要比dump文件大)



          3、 執行.mat提供的腳本

          ./ParseHeapDump.sh /home/xxx.hprof org.eclipse.mat.api:suspects

          (/home/xxx.hprof是dump文件的路徑)

          4、 在xxx.hprof目錄下,生成了java_pid32523_Leak_Suspects.zip壓縮文件

          5、 下載到windows下,解壓,打開index.html

          在分析頁面中可以看到,io.netty.channel.nio.NioEventLoopGroup對象占用了JVM中61.36%的空間。其次是io.netty.buffer.PoolThreadCache對象,占用了21.38%。

          看名字這倆對象都是netty框架中的類,在網上查了下資料,“NioEventLoopGroup”是netty中的一個線程池對象。

          看頁面上的統計,JVM中有1145個netty的線程池對象,這是什么操作?線程池不就一個就行了嗎?為什么有這么多?

          看到線程池對象,就想到會不會JVM線程方面有問題?因為腳本進程現在已經崩潰了,只能重新運行腳本,然后再對線程進行監控。

          腳本運行過程中,通過監控jvm,發現old區確實在不斷的緩慢增加,這樣長時間跑下去,應該就會重現昨天晚上的問題。

          執行jstack命令打印線程堆棧信息

          jstack pid > thread.log

          打開thread.log看了下,線程狀態倒沒啥問題,但是堆棧中有大量的nioEventLoopGroup線程,看編號有1000+,通過命令統計了下,確實有1000+個nioEventLoopGroup線程。



          這個數量跟上面MAT工具分析的實例數量也差不多對應上了,現在問題基本上就確定了。也就是說在內存泄漏發生前,JVM中存在1000+個nioEventLoopGroup線程,每個線程創建了一個NioEventLoopGroup對象,因為線程池的特性,所以這些線程處于都是運行狀態的。

          并且在腳本運行過程中發現,這個nioEventLoopGroup線程并不是開始就是1000+,而是從0慢慢漲上來的。也就是說隨著腳本的運行,慢慢積累上來的。

          這個時候目光又回到了我的腳本中,雖然并不是因為我不斷的new Demo對象造成了內存泄漏,但是肯定跟這個行為有關系,nioEventLoopGroup是netty框架用到的對象,于是就想到了代碼中的TClient client=new TClient(xxx);

          打開TClient的jar包看了下,在TClient的構造函數里,確實創建了一個nioEventLoopGroup對象



          然后在connect方法中,使用了這個線程池對象bossGroup



          現在基本上確定是什么原因了,如下:

          a> 每隔1分鐘,腳本會new一個Demo對象

          b> Demo對象的invoke方法里又new了一個TClient對象

          c> TClient對象內部在做netty連接初始化的時候,創建了NioEventLoopGroup線程池對象

          雖然腳本中創建的Demo對象和TClient對象都會被JVM回收,但是可能是因為netty使用NioEventLoopGroup線程池和服務端建立了長連接,導致線程池對象并不會被回收。這樣長時間跑下來,JVM中中的NioEventLoopGroup對象就會越來越多,最終導致了內存泄漏。

          這么來看,還真是每次new Demo間接帶來的影響。知道原因就好說了,Demo對象不能在每次運行的時候創建,而且放在類初始化的時候創建一個。無論腳本跑多少次,都只有一個NioEventLoopGroup對象了。

          重新修改了下腳本,長時間運行監控了下,確實內存使用很穩定,沒有出現內存泄漏的情況。

          問題似乎是得到了解決,但是等等。我腦海中突然又想到另外一個問題,雖然我在腳本中每次都創建一個TClient對象,但是每次跑完后,都會調用TClient的close方法啊,close方法里應該會釋放NioEventLoopGroup對象啊,難道沒做嗎?

          打開TClient的jar包看了下close方法



          在close方法中,確實把NioEventLoopGroup置為null了,對于一個普通的對象來說,只要對象引用為null,那么在下次JVM垃圾回收的時候,就會把這個對象回收掉。但是對于一個線程池對象來說,因為線程池中有活動線程存在,所以盡管置為null了,JVM也不會回收這個線程池。一般的線程池對象,都是通過shutdown方法來銷毀線程池的。

          查看了下netty的api文檔,確實有shutdownGracefully方法(優雅關閉)



          現在問題徹底搞清楚了,TClient的close方法中,只是簡單的將線程池對象置為null,并沒有進行shutdown操作,因此JVM并不能回收線程池對象。從而造成了,即便用戶調用了close方法,其實資源也沒有銷毀,最終自然就會出現內存泄漏。

          作為一個通用的工具包,內部的資源的釋放,并不能靠調用者來保證。理論上來說,即便我每次都new TClient對象,只要我都關閉了。在業務層面來說,也是正常行為。不能讓調用者必須緩存client對象,否則就會出現內存泄漏,這樣是不合理的。

          在跟相關開發溝通后,對代碼做了修改,加上了shutdown方法,仍然用老的腳本進行測試,在長時間的運行后,內存依然保持正常。因此這個問題終于解決了。

          最后總結一下

          1、 此問題的根本原因是client包中close方法沒有成功銷毀資源

          2、 理論上來說,重復創建大量對象并不會造成內存泄漏,但是如果代碼中同時也創建了第三方包的對象,在不了解其實現細節的情況了,可能其內部會創建一些不可被回收的對象,這個時候就會有內存泄漏的風險。因此還是盡量的復用對象,減少內存泄漏問題的發生。

          作 者:Testfan 北河

          出 處:微信公眾號:自動化軟件測試平臺

          版權說明:歡迎轉載,但必須注明出處,并在文章頁面明顯位置給出文章鏈接


          主站蜘蛛池模板: AV天堂午夜精品一区| 国产一区二区精品久久凹凸| 中日韩精品无码一区二区三区| 综合久久一区二区三区 | 亚洲丰满熟女一区二区哦| 国产情侣一区二区| 在线观看一区二区精品视频| 一区二区免费国产在线观看| 中文字幕色AV一区二区三区| 久久国产精品无码一区二区三区| 亚洲欧洲无码一区二区三区| 国产一区二区三区在线看片 | 亚洲AV色香蕉一区二区| 精品福利视频一区二区三区| 国产精品福利一区| 日本不卡免费新一区二区三区| 亚洲一区二区三区91| 日韩精品无码人妻一区二区三区| 麻豆精品久久久一区二区| 伊人久久一区二区三区无码| 日韩一区二区三区精品| 久久精品一区二区三区资源网| 精品国产亚洲一区二区三区在线观看| 99国产精品一区二区| 亚洲av色香蕉一区二区三区| 99久久精品费精品国产一区二区| 久久无码AV一区二区三区| 制服美女视频一区| 亚洲综合在线成人一区| 精品国产一区二区22| 蜜桃传媒一区二区亚洲AV| 国产亚洲一区二区精品| 国产午夜一区二区在线观看| 秋霞无码一区二区| 亚洲综合无码AV一区二区| 波多野结衣中文字幕一区| 3D动漫精品一区二区三区| 久久久91精品国产一区二区三区| 成人h动漫精品一区二区无码| 久久精品国产第一区二区三区 | 日韩社区一区二区三区|