高德客戶端及引擎技術架構演進與思考

2019杭州雲棲大會上,高德地圖技術團隊向與會者分享了包括視覺與機器智能、路線規劃、場景化/精細化定位、時空數據應用、億級流量架構演進等多個出行技術領域的熱門話題。現場火爆,聽眾反響強烈。我們把其中的優秀演講內容整理成文並陸續發布出來,本文為其中一篇。

阿里巴巴高級無線開發專家宋照春在高德技術專場做了題為《高德客戶端及引擎技術架構演進與思考》的演講,主要分享了高德地圖客戶端技術架構沿着「上漂下沉」、「模塊化、Bundle化」的思路演進所做的一系列架構升級中的經驗和思考。

以下為宋照春演講內容的簡版實錄:

主要分享三個方面的內容:

  • 融合
  • 架構治理
  • 動態化

一、三管齊下 深度融合

高德最初有兩個端,車機版的高德導航,手機版的高德地圖,兩個團隊,一個是2B,一個是2C,分別是汽車業務和手機業務。當時在引擎/技術上,分為離線引擎和在線引擎,但兩個團隊之間交流比較少,各自有自己的研發、產品和測試,而作為一款端上的APP,兩塊業務都需要有地圖渲染、路線規劃、導航以及定位等通用能力。從公司層面看,存在較大的重複建設,整體研發效率較低。

於是我們做了一件事:利用技術手段,打通端上引擎,打造一套能同時支撐多端的APP能力。具體到執行層面,先從A團隊拉一部分人到B團隊一起建設,建設完之後再從B團隊拉到A團隊。在同時支撐好主線業務發展的情況下,通過一年左右時間,完成了引擎上的融合,做到同時支撐手機、車機以及開放平台。

這樣就從引擎的維度,實現了渲染、定位、規劃和引導的統一。具體來說,我們的各大引擎有好多套代碼,好幾個開發團隊,每個團隊有各自的開發方式和開發環境(Linux,Windows,Mac OS)。各種開發環境,工程配置文件大量重複,修改非常繁瑣。

為此,我們通過兩種方法:

1.建立了一套構建系統Abtor,通過一個配置系統實現統一構建,能夠同時支持多個子引擎,在構建集成效率上得到了很大的提升;

2.對基礎庫進行了整體重構,形成了一套涵蓋了文件I/O、KV存儲、多線程框架&異步框架、歸檔、基礎容器等一系列標準能力的基礎庫,同時也做了引擎核心架構的統一。

 

二、架構治理

通過引擎的融合同時支持多端,在研發效率上實現比較大的收益。而通過技術的抓手來實現團隊的融合,對公司發展而言,這其實是更大的收益,團隊融合的意義在於人才拉通和復用,組織效率得到了較大提升。

隨着高德業務的快速發展,業務上持續擴品類,需求量激增,高德地圖從最初的駕車導航,到後來的步行、騎行、摩托車導航等等,App所承載的業務發展非常快,而原有的架構治理模式的問題也逐漸暴露出來。

首先就是App的代碼規模變得特別大。當時一個倉庫達到了10G以上,由此導致的一個典型的問題就是編譯慢,編譯出一次安裝包需要一個小時。伴隨代碼規模的另一個問題是團隊規模快速增長。代碼增長和大團隊并行開發,最終導致合版慢,每次迭代,客戶端合版需要2天。

代碼膨脹導致的架構腐化問題特別突出,所以測試質量以及線上的質量有段時間也比較差。此外,從產品提出需求到上線,平均需要45天,版本迭代周期很長。

為解決以上架構問題,我們採取了三個手段:升級Native基礎組件,搭建Native容器和頁面框架,Bundle化分拆(微應用)。

下面重點介紹下頁面框架和微應用。

頁面框架主要借鑒和融合了Android和iOS的生命期管理機制。從高德地圖App架構看,下層模塊是一套標準地圖,所有上層業務都要基於地圖模塊開發。為確保上層業務低耦合、一致性,我們設計了一個頁面框架。

如上圖,左邊的Activity是Android的系統頁面控制器,右邊的UIViewController是iOS的系統頁面控制器,通過虛線連接比較,我們發現兩端的頁面狀態設計基本相同。

所以,我們在設計自己的頁面框架時沿用了這些系統頁面狀態,同時從命名上也保持一致,這樣可以讓Android和iOS原生開發的同學更容易理解和上手。

我們吸取了雙端各自的優點。比如,Android端頁面有四種啟動模式,但是iOS 端並沒有這些,我們就把Android的四種啟動模式運用到了iOS端;iOS端有Present特性,但是Android端沒有,那麼也把這種特性融合到Android端的頁面框架中;最後,還有一些小設計,比如Android的onResult設計,也可以借鑒融合到iOS端。

此外,我們還做了微應用,所謂微應用,首先是模塊化,就是把大模塊倉庫大模塊拆成一個個小的Bundle,除了實現模塊化,還主要實現以下幾個目標:

粒度:以業務為單位,以業務線為分組

編譯:二進制級別的產物,可獨立編譯、出包時鏈接

依賴:松耦合,以“服務”為導向,不關心模塊歸屬

而Native容器層面,要實現四個核心目標:路由管理、服務管理、UI生命期管理、微應用管理。

通過一年時間的Bundle化改造,高德地圖單端App完成了300多個頁面的建設,拆分了100多個Bundle。

從收益來看,總編譯時間從原來的60分鐘降低到了8分鐘,合版周期從原來的3天降到1天,需求上線周期降到了1個月以內,線上質量和測試質量都得到了極大的提升,崩潰率從萬分之八降低到十萬分之八。

三、動態化

隨着高德地圖業務發展沿着擴品類、在垂直品類做精做細,景區、酒店、銀行商鋪、充電樁等個性化定製需求凸顯,對前端展現提出了更高的要求,對“快速應變”要求也更高了。

實際上,在2015年,高德就開始做動態化。最早的時候業內就有React Native,團隊做了技術調研,發現不能完全滿足業務上的需要,尤其是性能方面。最後我們決定自研一套動態化技術。

具體來說,就是通過一個核心C++引擎,把兩端業務(Android、iOS)用一套JavaScript代碼解決,實現雙端歸一,Android實現業務動態化發布。

架構層面,最下面是高德App核心的地圖引擎,我們在上面搭建了一套動態化應用引擎,通過C++來實現。應用引擎的作用是為了承上啟下,上面承載動態化業務,下層完成地圖引擎的直接打通。眾所周知,GUI的核心是DOM樹,所以應用引擎不但要實現和JavaScript引擎的整合,還要負責DOM樹的核心邏輯計算。

其次,動態化的技術和前端Web技術一致:樣式、布局。應用引擎負責完成樣式的布局計算、DOM樹Diff、事件生成。而GUI的繪製,通過Diff事件,交由原生的Android以及iOS去完成。這樣,所有的GUI都是原生的組件。

在之上,我們搭建了一套前端框架,前端框架採用當前前端響應式框架做,前端框架之上又搭建了一套前端的UI卡片庫和UI組件庫,讓上層業務能夠更高效的開發。

而對於一些通過動態化的技術無法實現,或者性能上存在卡點的功能,我們就通過Native擴展能力來支撐,這樣,完整的動態化的業務能夠直接運行在Android以及iOS上。

 

JS去執行代碼之後,前端框架會產生虛擬的DOM樹,最後提交到C++引擎,形成C++的DOM樹。C++引擎去完成布局、樣式計算,Diff計算,將每個節點的屬性和坐標交給Android以及iOS,由Native來完成最終UI的渲染。

總體來說,動態化的特點:首先是它與主流前端框架融合,充分融合了大前端的生態;第二,性能、擴展性較好。因為採用C++實現整個核心邏輯,靜態和動態的語言綁定技術,能夠保證地圖引擎的能力能夠直接透出到上層,或者從上層能夠直接call底層的C++能力;第三,多端歸一和動態化,充分利用Native優勢,接近原生Native體驗。

動態化技術改造完成之後,雙端不一致的問題降低了90%,開發、測試成本降低30%,發版周期從T+30到T+0。

最後,總結下高德客戶端及引擎技術架構演進的幾個重要階段:第一個階段,通過在線&離線引擎的融合拉通,讓高德最核心的導航能力提到提升;第二階段,在客戶端發展成為“巨型”APP,代碼量發展到超大規模的時候,通過架構治理,滿足業務快速增長的訴求,解決大規模業務體量下的架構合理性問題,消除架構瓶頸;第三個階段通過動態化的技術,實現多端歸一,以及動態發版能力,為業務發展提供更大的助力。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

美國推出全球首個可移動光伏發電車棚

Envision Solar公司開發了全球首個可移動的光伏發電車棚系統EV ARC (Electric Vehicle Autonomous Renewable Charger),EV ARC長4.88m、寬2.74m,正好收納停車位內。該車棚配備2.5kW或3.3kW的太陽能電池,年發電量為3800~7000kWh,另外,該系統還配備了21.6kWh的蓄電池。   Envision Solar的Desmond Wheatley介紹,“ARC無需打地基和鋪設電纜等等土木施工。也無需更新變壓器和開關裝置。而且ARC的尺寸就是一個車位大小,因此設置充電樁,不會使寶貴的車位減少”。   EV ARC利用該公司開發的配備水壓控制功能、類似於托運船隻使用的拖車(名為ARC Mobility)運到目的地,設置在指定的停車場,5分鐘內就能完成充電樁的設置。   目前,穀歌已經開始使用EV ARC。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

Java程序線上故障排查

目錄

這篇文章是在公司做了不少的線上Java服務故障排查和優化之後的一個總結,可以作為一個工具清單,在分析問題的時候需要有整體思路:全局觀,先從系統層面入手,大致定位方向(內存,cpu,磁盤,網絡),然後再去分析具體的進程。

一、Linux

內存和cpu

內存和cpu問題是出問題最多的一個點,因為有些命令如top同時可以觀察到內存和cpu所以放在一起。

top命令

常用參數: -H 打印具體的線程, -p 打印某個進程 進入后 按数字1 可以切換cpu的圖形看有幾個核

下面是我的測試環境shell:

top - 14:28:49 up 7 min,  3 users,  load average: 0.08, 0.26, 0.19
Tasks: 221 total,   2 running, 219 sleeping,   0 stopped,   0 zombie
%Cpu(s):  5.1 us,  3.4 sy,  0.0 ni, 91.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   985856 total,    81736 free,   646360 used,   257760 buff/cache
KiB Swap:  2094076 total,  1915196 free,   178880 used.   141592 avail Mem 

我一般重點關注的指標有:

%Cpu(s): 5.1 us, 3.4 sy, 0.0 wa

這裏可以非常直觀的看到當前cpu的負載情況,us用戶cpu佔用時間,sy是系統調用cpu佔用時間,wa是cpu等待io的時間,前面兩個比較直觀,但是第三個其實也很重要,如果wa很高,那麼你就該重點關注下磁盤的負載了,尤其是像mysql這種服務器。

load average: 0.08, 0.26, 0.19

cpu任務隊列的負載,這個隊列包括正在運行的任務和等待運行的任務,三個数字分別是1分鐘、5分鐘和15分鐘的平均值。這個和cpu佔用率一般是正相關的,反應的是用戶代碼,如果超過了內核數,表示系統已經過載。也就是說如果你是8核,那麼這個数字小於等於8的負載都是沒問題的,我看網上的建議一般這個值不要超過ncpu*2-2為好。

KiB Mem : 985856 total, 81736 free, 646360 used, 257760 buff/cache

內存佔用情況,total總內存,free空餘內存, used已經分配內存,buff/cache塊設備和緩衝區佔用的內存,因為Linux的內存分配,如果有剩餘內存,他就會將內存用於cache,這樣可以較少磁盤的讀寫提高效率,如果有應用申請內存,buff/cache這部分內存也是可用的,所以正真的剩餘內存應該是free+buff/cache

swap

線上服務器一般都是禁用狀態,所以不用看這項。

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

這一欄主要是看進程的詳情,重點是%CPU %MEM,上面看的是整個服務器的負載,這裡是每個進程的負載。還有看看S這個指標,這個代碼了進程的狀態,有時候有些進程會出現T(暫停)這個狀態。

網絡

ss

netstat的高性能版,參數都基本一致

常用參數: -n 打印数字端口號 -t tcp連接 -l 監聽端口 -a 所有端口 -p 進程號 -s 打印統計信息

ss -s示例:

Total: 1732 (kernel 1987)
TCP:   42373 (estab 1430, closed 40910, orphaned 2, synrecv 0, timewait 40906/0), ports 1924
Transport Total     IP        IPv6
*     1987      -         -        
RAW   18        9         9        
UDP   18        11        7        
TCP   1463      503       960     

可以看到整體的連接情況,如timewait過高,連接數過高等情況

然後使用ss -ntap|grep 進程號 or 端口號查看進程的連接

ping

查看時延和丟包情況

mtr

查看丟包請求

磁盤

磁盤問題在mysql服務器中非常常見,很多時候mysql服務器的CPU不高但是卻出現慢查詢日誌飆升,就是因為磁盤出現了瓶頸。還有mysql的備份策略,如果沒有監控磁盤空間,可能出現磁盤滿了服務不可用的現象。

iostat命令

常用參數: -k 用kb為單位 -d 監控磁盤 -x显示詳情 num count 每個幾秒刷新 显示次數

這個是我查看磁盤負載的主要工具,也可以显示cpu的負載,不過我一般用iostat -kdx 2 10,下面是我測試環境執行情況:

root@ubuntu:~# iostat -kdx 2 10
Linux 4.13.0-38-generic (ubuntu)    11/18/2018  _x86_64_    (1 CPU)
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda              24.75   196.05  121.66    9.75  2481.33   961.29    52.40     0.44    3.33    1.12   30.95   0.51   6.71
scd0              0.00     0.00    0.02    0.00     0.08     0.00     7.00     0.00    0.25    0.25    0.00   0.25   0.00

我一般重點關注的指標有:

  1. rkB/s和wkB/s: 分別對應讀寫速度
  2. avgqu-sz: 讀寫隊列的平均請求長度,可以類比top命令的load average
  3. await r_await w_await: io請求的平均時間(毫秒),分別是讀寫,讀和寫三個平均值。這個時間都包括在隊列中等待的時間和實際處理讀寫請求的時間,還有svctm這個參數,他說的是實際處理讀寫請求的時間,照理來講w_await肯定是大於svctm的,但是我在線上看到有w_await小於svctm的情況,不知道是什麼原因。我看iostat的man手動中說svctm已經廢棄,所以一般我看的是這三個。
  4. %util: 這個參數直觀的看磁盤的負載情況,我首先看的就是這個參數。和top的wa命令有關聯。

df

查看文件系統的容量

常用參數: -h 友好的單位 如Kb,Mb等

du

統計具體的文件大小

常用參數: -h 友好的單位 如Kb,Mb等 -s 總計,而不是進入每個子目錄分別統計

場景:例如系統磁盤空間不足時,先通過df命令定位到具體的掛載目錄,在進去掛載目錄后,使用
du -sh *查看各個文件或者子目錄的大小定位具體文件

這裏還有ls命令,可以通過加-h和-S(按大小排序)

iostat命令

常用參數: -k 用kb為單位 -d 監控磁盤 -x显示詳情 num count 每個幾秒刷新 显示次數

這個是我查看磁盤負載的主要工具,也可以显示cpu的負載,不過我一般用iostat -kdx 2 10,下面是我測試環境執行情況:

root@ubuntu:~# iostat -kdx 2 10
Linux 4.13.0-38-generic (ubuntu)    11/18/2018  _x86_64_    (1 CPU)
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda              24.75   196.05  121.66    9.75  2481.33   961.29    52.40     0.44    3.33    1.12   30.95   0.51   6.71
scd0              0.00     0.00    0.02    0.00     0.08     0.00     7.00     0.00    0.25    0.25    0.00   0.25   0.00

我一般重點關注的指標有:

  1. rkB/s和wkB/s: 分別對應讀寫速度
  2. avgqu-sz: 讀寫隊列的平均請求長度,可以類比top命令的load average
  3. await r_await w_await: io請求的平均時間(毫秒),分別是讀寫,讀和寫三個平均值。這個時間都包括在隊列中等待的時間和實際處理讀寫請求的時間,還有svctm這個參數,他說的是實際處理讀寫請求的時間,照理來講w_await肯定是大於svctm的,但是我在線上看到有w_await小於svctm的情況,不知道是什麼原因。我看iostat的man手動中說svctm已經廢棄,所以一般我看的是這三個。
  4. %util: 這個參數直觀的看磁盤的負載情況,我首先看的就是這個參數。和top的wa命令有關聯。

lsof

列出當前系統打開文件,因為在linux下一切皆是文件,連接,硬件等均被描述為文件,所以這個命令也十分有用。

常用參數:

  1. -p 查看某個進程的文件
  2. 直接加文件名 查看哪些進程打開了文件
  3. +d 目錄 查看哪些進程打開了目錄以及下面的文件(不遞歸,+D是遞歸)

Sar
最後補充一個sar(System Activity Reporter)命令,如果系統沒有一個良好的監控,那麼這個命令對於排查問題是很好的補充,很多時候去排查問題的時候發現問題已經沒了,可以通過這個命令查看系統的活動情況,比如各個時間段cpu情況,內存情況。

常用參數:

  1. -r 內存信息
  2. -q loader信息,運行隊列情況
  3. -u cpu信息
  4. -W Swap換頁情況

/proc文件系統

/proc是個虛擬文件系統,是內核的一些數據,很多linux命令的都是通過解析/proc文件系統實現的,每個進程都會有一個以pid為目錄名的子目錄存在,通過解析/proc下的進程目錄可以得到很多進程的設置信息和資源佔用信息等。

這裏簡單說個排查過的問題,當時我們線上有個服務,正常ssh登錄的情況下,我們設置了ulimit中的open files為(進程可打開的最大描述符數量)100000,但是有一次在服務的日誌中發現有報錯說文件描述符不夠用。所以

二、JVM

java -XX:+PrintFlagsInitial 可以查看所以的jvm默認參數,其中帶有manageable表示運行時可以動態修改。

20:45 [root@centos]$ java -XX:+PrintFlagsInitial |grep manageable
     intx CMSAbortablePrecleanWaitMillis            = 100                                 {manageable}
     intx CMSTriggerInterval                        = -1                                  {manageable}
     intx CMSWaitDuration                           = 2000                                {manageable}
     bool HeapDumpAfterFullGC                       = false                               {manageable}
     bool HeapDumpBeforeFullGC                      = false                               {manageable}
     bool HeapDumpOnOutOfMemoryError                = false                               {manageable}
    ccstr HeapDumpPath                              =                                     {manageable}
    uintx MaxHeapFreeRatio                          = 70                                  {manageable}
    uintx MinHeapFreeRatio                          = 40                                  {manageable}
     bool PrintClassHistogram                       = false                               {manageable}
     bool PrintClassHistogramAfterFullGC            = false                               {manageable}
     bool PrintClassHistogramBeforeFullGC           = false                               {manageable}
     bool PrintConcurrentLocks                      = false                               {manageable}
     bool PrintGC                                   = false                               {manageable}
     bool PrintGCDateStamps                         = false                               {manageable}
     bool PrintGCDetails                            = false                               {manageable}
     bool PrintGCID                                 = false                               {manageable}
     bool PrintGCTimeStamps                         = false                               {manageable}

Java堆和垃圾收集器

java內存結構

堆內存結構:

java8元空間改動:

java 7種垃圾收集器:

常見搭配:

  1. java8默認:Parallel Scavenge和 Parallel Old
  2. 低延遲:ParNew和CMS
  3. java8以後可以直接使用G1,參數比較簡單

ParNew

Serial的并行版本

Parallel Scavenge

注重的是吞吐量,吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間),其具有自適應的特性

  1. 控制最大垃圾收集停頓時間的-XX:MaxGCPauseMillis參數
    MaxGCPauseMillis參數允許的值是一個大於0的毫秒數,收集器將儘力保證內存回收花費的時間不超過設定值。不過大家不要異想天開地認為如果把這個參數的值設置得稍小一點就能使得系統的垃圾收集速度變得更快,GC停頓時間縮短是以犧牲吞吐量和新生代空間來換取的:系統把新生代調小一些,收集300MB新生代肯定比收集500MB快吧,這也直接導致垃圾收集發生得更頻繁一些,原來10秒收集一次、每次停頓100毫秒,現在變成5秒收集一次、每次停頓70毫秒。停頓時間的確在下降,但吞吐量也降下來了。

  2. 直接設置吞吐量大小的 -XX:GCTimeRatio參數
    GCTimeRatio參數的值應當是一個大於0小於100的整數,也就是垃圾收集時間佔總時間的比率。如果把此參數設置為19,那允許的最大GC時間就佔總時間的5%(即1 /(1+19)),默認值為99,就是允許最大1%(即1 /(1+99))的垃圾收集時間。

  3. UseAdaptiveSizePolicy開關參數
    -XX:+UseAdaptiveSizePolicy是一個開關參數,當這個參數打開之後,就不需要手工指定新生代的大小(-Xmn)、Eden與Survivor區的比例(-XX:SurvivorRatio)、晉陞老年代對象年齡(-XX:PretenureSizeThreshold)等細節參數了,虛擬機會根據當前系統的運行情況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或最大的吞吐量,這種調節方式稱為GC自適應的調節策略(GC Ergonomics)。

說說UseAdaptiveSizePolicy參數,加了這個參數-XX:SurvivorRatio會失效,所以有些人會發現新生代比例未如自己的預期,而UseAdaptiveSizePolicy有默認是開啟的

CMS

併發垃圾收集器,注重的是時延,有分配擔保失敗的風險

CMS收集器的GC周期由6個階段組成。其中4個階段(名字以Concurrent開始的)與實際的應用程序是併發執行的,而其他2個階段需要暫停應用程序線程。

初始標記:為了收集應用程序的對象引用需要暫停應用程序線程,該階段完成后,應用程序線程再次啟動。
併發標記:從第一階段收集到的對象引用開始,遍歷所有其他的對象引用。
併發預清理:改變當運行第二階段時,由應用程序線程產生的對象引用,以更新第二階段的結果。
重標記:由於第三階段是併發的,對象引用可能會發生進一步改變。因此,應用程序線程會再一次被暫停以更新這些變化,並且在進行實際的清理之前確保一個正確的對象引用視圖。這一階段十分重要,因為必須避免收集到仍被引用的對象。
併發清理:所有不再被應用的對象將從堆里清除掉。
併發重置:收集器做一些收尾的工作,以便下一次GC周期能有一個乾淨的狀態。

  1. -XX:CMSInitiatingOccupancyFraction=90 (jdk1.5默認值68,1.6開始默認值92,指設定CMS在對內存佔用率達到70%的時候開始GC(因為CMS會有浮動垃圾,所以一般都較早啟動GC)
  2. -XX:+UseCMSInitiatingOccupancyOnly 只是用設定的回收閾值(上面指定的70%),如果不指定,JVM僅在第一次使用設定值,後續則自動調整
  3. -XX:+CMSScavengeBeforeRemark 在CMS GC前啟動一次ygc,目的在於減少old gen對ygc gen的引用,降低remark時的開銷
  4. -XX:+CMSParallelRemarkEnabled 併發標記
  5. -XX:+ExplicitGCInvokesConcurrent命令JVM無論什麼時候調用系統GC(system.gc()),都執行CMS GC,而不是Full GC
  6. -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses保證當有系統GC調用時,永久代也被包括進CMS垃圾回收的範圍內
  7. -XX:UseParNewGC 使用CMS時自動開啟,因為CMS不能和Parallel Scavenge搭配使用

上面的參數都建議開啟,CMS需要注意的一個問題就是CMSInitiatingOccupancyFraction參數,這個參數直接影響CMS回收老年代的時機,需要結合自己的業務場景來調整,一般情況下應該盡量設置大一點,但是有一個嚴重的問題,就是浮動垃圾的問題,如果CMS在併發收集的時候出現老年代不能存放晉陞對象將直接進行Full GC使用Serial Old垃圾收集器,所以不能一味追求最大化,如果老年代增長比較慢,那麼可以設置的稍微較大些,如果增長比較快,可以從增大新生代,調低CMSInitiatingOccupancyFraction入手

最後在提下-XX:+DisableExplicitGC :禁用显示gc (system.gc())這個參數,很多人因為system.gc()會導致Full gc而禁用显示調用gc,但是這個參數最好不要禁用,現在很多服務端程序都使用了Nio,jvm為了減少內存拷貝,採用了直接內存,直接內存屬於堆外內存,java大多使用了Netty這個框架,他幫我們處理堆外內存的回收,實現的機制就是通過調用system.gc(),發起Full Gc,Full Gc會回收堆外內存,如果將system.gc()禁用,則得等到Full Gc發生才能回收堆外內存,很有可能出現堆外內存佔用過高影響系統性能或者因為內存不足被系統Kill的問題。

gc日誌參數

  1. -XX:+PrintGC 輸出GC日誌
  2. -XX:+PrintGCDetails 輸出GC的詳細日誌
  3. -XX:+PrintGCTimeStamps 輸出GC的時間戳(以基準時間的形式)
  4. -XX:+PrintGCDateStamps 輸出GC的時間戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
  5. -XX:+PrintHeapAtGC 在進行GC的前後打印出堆的信息
  6. -XX:+PrintGCApplicationStoppedTime // 輸出GC造成應用暫停的時間
  7. -Xloggc:../logs/gc.log 日誌文件的輸出路徑
  8. -XX:+PrintTenuringDistribution 打印新生代的年齡分佈(這裏需要注意,如果使用的是Parallel Scavenge,那麼打印的時候是沒有年齡分佈信息的)
  9. -XX:+UseGCLogFileRotation 開啟日誌輪換
  10. -XX:NumberOfGCLogFiles=5 日誌保留數量
  11. -XX:GCLogFileSize=10m 每份日誌保留大小

堆參數

  1. -Xms 最小堆大小
  2. -Xmx 最大堆大小
  3. -Xmn 新生代大小
  4. -XX:SurvivorRatio 新生代中Eden區與Survivor區的比例,默認值為8

gc日誌分析

ParNew Gc日誌:

{Heap before GC invocations=4196 (full 3):
 par new generation   total 1887488K, used 1683093K [0x0000000640000000, 0x00000006c0000000, 0x00000006c0000000)
  eden space 1677824K, 100% used [0x0000000640000000, 0x00000006a6680000, 0x00000006a6680000)
  from space 209664K,   2% used [0x00000006a6680000, 0x00000006a6ba5430, 0x00000006b3340000)
  to   space 209664K,   0% used [0x00000006b3340000, 0x00000006b3340000, 0x00000006c0000000)
 concurrent mark-sweep generation total 4194304K, used 1565111K [0x00000006c0000000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 59881K, capacity 64953K, committed 66588K, reserved 1107968K
  class space    used 6615K, capacity 7729K, committed 8224K, reserved 1048576K
2019-10-29T23:48:00.181+0800: 27966.548: [GC (Allocation Failure) 2019-10-29T23:48:00.181+0800: 27966.548: [ParNew
Desired survivor size 107347968 bytes, new threshold 15 (max 15)
- age   1:    2287832 bytes,    2287832 total
- age   2:     132752 bytes,    2420584 total
- age   3:     102408 bytes,    2522992 total
- age   4:     125768 bytes,    2648760 total
- age   5:     145464 bytes,    2794224 total
- age   6:      82808 bytes,    2877032 total
- age   7:     104736 bytes,    2981768 total
- age   8:      79216 bytes,    3060984 total
- age   9:      89496 bytes,    3150480 total
- age  10:      81864 bytes,    3232344 total
- age  11:      91304 bytes,    3323648 total
- age  12:      78912 bytes,    3402560 total
- age  13:      80960 bytes,    3483520 total
- age  14:      91560 bytes,    3575080 total
- age  15:      78992 bytes,    3654072 total
: 1683093K->5343K(1887488K), 0.0342117 secs] 3248204K->1570530K(6081792K), 0.0343754 secs] [Times: user=0.17 sys=0.01, real=0.03 secs]
Heap after GC invocations=4197 (full 3):
 par new generation   total 1887488K, used 5343K [0x0000000640000000, 0x00000006c0000000, 0x00000006c0000000)
  eden space 1677824K,   0% used [0x0000000640000000, 0x0000000640000000, 0x00000006a6680000)
  from space 209664K,   2% used [0x00000006b3340000, 0x00000006b3877f50, 0x00000006c0000000)
  to   space 209664K,   0% used [0x00000006a6680000, 0x00000006a6680000, 0x00000006b3340000)
 concurrent mark-sweep generation total 4194304K, used 1565186K [0x00000006c0000000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 59881K, capacity 64953K, committed 66588K, reserved 1107968K
  class space    used 6615K, capacity 7729K, committed 8224K, reserved 1048576K
}

gc日誌中打印了新生代,老年代和元空間等內存信息,其中Times: user=0.02 sys=0.01, real=0.01 secs三個時間分別是用戶態的時間,內核態的時間和牆鍾時間。牆鍾時間表示真正過去的時間,而用戶態和內核態的時間則是乘了相應的cpu核心數。

CMS GC日誌:

2019-10-29T18:03:19.578+0800: 7285.945: [GC (CMS Initial Mark) [1 CMS-initial-mark: 3182477K(4194304K)] 3254261K(6081792K), 0.0044508 secs] [Times: user=0.01 sys=0.01, real=0.00 secs]
2019-10-29T18:03:19.582+0800: 7285.949: [CMS-concurrent-mark-start]
2019-10-29T18:03:20.812+0800: 7287.179: [CMS-concurrent-mark: 1.229/1.229 secs] [Times: user=3.86 sys=0.46, real=1.23 secs]
2019-10-29T18:03:20.812+0800: 7287.179: [CMS-concurrent-preclean-start]
2019-10-29T18:03:20.823+0800: 7287.190: [CMS-concurrent-preclean: 0.011/0.011 secs] [Times: user=0.03 sys=0.01, real=0.01 secs]
2019-10-29T18:03:20.823+0800: 7287.190: [CMS-concurrent-abortable-preclean-start]
{Heap before GC invocations=896 (full 3):
 par new generation   total 1887488K, used 1747877K [0x0000000640000000, 0x00000006c0000000, 0x00000006c0000000)
  eden space 1677824K, 100% used [0x0000000640000000, 0x00000006a6680000, 0x00000006a6680000)
  from space 209664K,  33% used [0x00000006a6680000, 0x00000006aaae9780, 0x00000006b3340000)
  to   space 209664K,   0% used [0x00000006b3340000, 0x00000006b3340000, 0x00000006c0000000)
 concurrent mark-sweep generation total 4194304K, used 3182477K [0x00000006c0000000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 60431K, capacity 66281K, committed 66588K, reserved 1107968K
  class space    used 6828K, capacity 8138K, committed 8224K, reserved 1048576K
2019-10-29T18:03:25.649+0800: 7292.016: [GC (Allocation Failure) 2019-10-29T18:03:25.649+0800: 7292.016: [ParNew
Desired survivor size 107347968 bytes, new threshold 15 (max 15)
- age   1:    1362152 bytes,    1362152 total
- age   3:     124920 bytes,    1487072 total
- age   4:     115256 bytes,    1602328 total
- age   5:     165000 bytes,    1767328 total
- age   6:      99776 bytes,    1867104 total
- age   7:      97728 bytes,    1964832 total
- age   8:      94616 bytes,    2059448 total
- age   9:      93176 bytes,    2152624 total
- age  10:     111352 bytes,    2263976 total
- age  11:     127800 bytes,    2391776 total
- age  12:      85248 bytes,    2477024 total
- age  13:     110984 bytes,    2588008 total
- age  14:     101880 bytes,    2689888 total
- age  15:      96288 bytes,    2786176 total
: 1747877K->18163K(1887488K), 0.0364969 secs] 4930355K->3200776K(6081792K), 0.0366162 secs] [Times: user=0.17 sys=0.00, real=0.04 secs]
Heap after GC invocations=897 (full 3):
 par new generation   total 1887488K, used 18163K [0x0000000640000000, 0x00000006c0000000, 0x00000006c0000000)
  eden space 1677824K,   0% used [0x0000000640000000, 0x0000000640000000, 0x00000006a6680000)
  from space 209664K,   8% used [0x00000006b3340000, 0x00000006b44fcd88, 0x00000006c0000000)
  to   space 209664K,   0% used [0x00000006a6680000, 0x00000006a6680000, 0x00000006b3340000)
 concurrent mark-sweep generation total 4194304K, used 3182613K [0x00000006c0000000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 60431K, capacity 66281K, committed 66588K, reserved 1107968K
  class space    used 6828K, capacity 8138K, committed 8224K, reserved 1048576K
}
 CMS: abort preclean due to time 2019-10-29T18:03:25.825+0800: 7292.192: [CMS-concurrent-abortable-preclean: 4.952/5.002 secs] [Times: user=10.51 sys=1.44, real=5.01 secs]
2019-10-29T18:03:25.826+0800: 7292.193: [GC (CMS Final Remark) [YG occupancy: 81039 K (1887488 K)]2019-10-29T18:03:25.826+0800: 7292.194: [Rescan (parallel) , 0.0142974 secs]2019-10-29T18:03:25.841+0800: 7292.208: [weak refs processing, 0.0019208 secs]2019-10-29T18:03:25.843+0800: 7292.210: [class unloading, 0.0230836 secs]2019-10-29T18:03:25.866+0800: 7292.233: [scrub symbol table, 0.0054818 secs]2019-10-29T18:03:25.871+0800: 7292.238: [scrub string table, 0.0707817 secs][1 CMS-remark: 3182613K(4194304K)] 3263652K(6081792K), 0.1182958 secs] [Times: user=0.17 sys=0.01, real=0.11 secs]
2019-10-29T18:03:25.946+0800: 7292.313: [CMS-concurrent-sweep-start]
2019-10-29T18:03:27.771+0800: 7294.138: [CMS-concurrent-sweep: 1.825/1.826 secs] [Times: user=3.98 sys=0.52, real=1.82 secs]
2019-10-29T18:03:27.771+0800: 7294.138: [CMS-concurrent-reset-start]
2019-10-29T18:03:27.781+0800: 7294.148: [CMS-concurrent-reset: 0.010/0.010 secs] [Times: user=0.02 sys=0.01, real=0.01 secs]

JVMTI介紹

JVM相關參數:

 -agentlib:<庫名>[=<選項>]
                  加載本機代理庫 <庫名>, 例如 -agentlib:jdwp
                  另請參閱 -agentlib:jdwp=help
-agentpath:<路徑名>[=<選項>]
                  按完整路徑名加載本機代理庫
-javaagent:<jar 路徑>[=<選項>]
                  加載 Java 編程語言代理, 請參閱 java.lang.instrument

JVMTI(Java Virtual Machine Tool Interface)即指Java虛擬機工具接口,它是一套由虛擬機直接提供的 native 接口,通過這些接口,開發人員不僅調試在該虛擬機上運行的 Java 程序,還能查看它們運行的狀態,設置回調函數,控制某些環境變量(JMX),從而優化程序性能。Java Agent就是基於JVMTI的,所以眾多基於Java Agent的技術例如APM,遠程調試,各種性能剖析同樣是基於這個技術。

JVMTI 接口:

JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options, void *reserved);

JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM* vm, char* options, void* reserved);

JNIEXPORT void JNICALL
Agent_OnUnload(JavaVM *vm); 

-agentpath是c/c++編寫的動態庫,-agentlib和-javaagent是一個instrument的JVMTIAgent(linux下對應的動態庫是libinstrument.so)。

Attach機制

Jvm提供一種jvm進程間通信的能力,能讓一個進程傳命令給另外一個進程,並讓它執行內部的一些操作,比如說我們為了讓另外一個jvm進程把線程dump出來,那麼我們跑了一個jstack的進程,然後傳了個pid的參數,告訴它要哪個進程進行線程dump。

Attach命令列表

static AttachOperationFunctionInfo funcs[] = {
  { "agentProperties",  get_agent_properties },
  { "datadump",         data_dump },
  { "dumpheap",         dump_heap },
  { "load",             JvmtiExport::load_agent_library },
  { "properties",       get_system_properties },
  { "threaddump",       thread_dump },
  { "inspectheap",      heap_inspection },
  { "setflag",          set_flag },
  { "printflag",        print_flag },
  { "jcmd",             jcmd },
  { NULL,               NULL }
};

Attach流程:

Jstack源碼:
https://android.googlesource.com/platform/libcore/+/0ebbfbdbca73d6261a77183f68e1f3e56c339f9f/ojluni/src/main/java/sun/tools/jstack/JStack.java

查看java線程:

其中Siginal Dispatcher是處理進程信號的線程,Attach Listener正式Attach機制處理線程。

java自帶工具

jps

查看Java進程列表

常用參數:

  1. -l: 輸出應用程序主類完整package名稱或jar完整名稱
  2. -m:輸出主函數傳入的參數

jmap

查看JVM堆的情況

常用參數:

  1. -heap
  2. -dump 這個命令還有兩個常用參數
    1. live 只dump存活對象,會導致GC
    2. file=file dump文件名

示例:jmap -dump:live,file=heap.dump <pid>

這裡有兩點,一方面需要注意live會導致GC,有時候在查問題的時候可能不是你預期的效果,一般查內存問題時不加這個選項,另外dump文件如果比較大,可以先壓縮在傳回本地

jstack

查看JVM的堆棧情況,監測死鎖等

這個命令比較簡單,一般不用加什麼參數,有時候JVM沒響應時可以加-F參數。一般這個命令可以結合top,在top定位到佔用cpu高的線程后,在具體在Jstack打印的堆棧中查看線程,有時候也需要多次打印堆棧來進行對比

jstat

查看JVM gc信息,觀察JVM的GC活動

常用參數: -gccause 這個參數包含了-gcutil的信息多了一個gc原因

示例: jstat -gccause <pid> 1000

11:19 [supertool@y051]$ jstat -gccause  10711 1000
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC                 
  0.00  21.23  95.99  69.88  91.56  82.62   1187   22.511     4    0.141   22.652 Allocation Failure   No GC               
  0.00  21.23  99.51  69.88  91.56  82.62   1187   22.511     4    0.141   22.652 Allocation Failure   No GC               
 21.30   0.00   3.51  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               
 21.30   0.00   7.02  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               
 21.30   0.00  10.14  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               
 21.30   0.00  13.62  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               
 21.30   0.00  16.78  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               

jinfo

查看設置的JVM參數和啟動時的命令行參數,還可以動態修改JVM參數

常用參數

  1. -flags 查看jvm參數值
  2. -sysprops 查看系統屬性值

示例:jinfo -flags 10711

Non-default VM flags: -XX:BiasedLockingStartupDelay=0 -XX:CICompilerCount=4 -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=75 -XX:+CMSParallelRemarkEnabled -XX:ErrorFile=null -XX:GCLogFileSize=10485760 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=null -XX:InitialHeapSize=1073741824 -XX:MaxHeapSize=1073741824 -XX:MaxNewSize=268435456 -XX:MaxTenuringThreshold=15 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=268435456 -XX:NumberOfGCLogFiles=20 -XX:OldPLABSize=16 -XX:OldSize=805306368 -XX:+PrintClassHistogram -XX:+PrintCommandLineFlags -XX:+PrintConcurrentLocks -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:StringTableSize=6000000 -XX:+UseBiasedLocking -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseFastUnorderedTimeStamps -XX:+UseGCLogFileRotation -XX:+UseParNewGC 
Command line:  -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 -XX:+PrintCommandLineFlags -Xms1g -Xmx1g -Xmn256m -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -Dfile.encoding=UTF-8 -XX:MaxTenuringThreshold=15 -XX:StringTableSize=6000000  -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC -XX:+PrintClassHistogram -XX:+PrintConcurrentLocks -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=20 -XX:GCLogFileSize=10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/java/logs -XX:ErrorFile=/var/java/logs/jvm-error.log -Dlog4j.config.file=log4j_.properties -Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.Log4jLogDelegateFactory -Dvertx.options.maxEventLoopExecuteTime=100000000 -Dvertx.options.warningExceptionTime=300000000 

JDPA(Java Platform Debugger Architecture)

java遠程調試,需要jvm啟動時加參數:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005

遠程調試非常有用,有時候測試環境很難復現時,可以用通過遠程調試查看線程數據

三、三方工具

jprofile

CPU性能分析

抽樣:每隔一段時間,獲取線程棧,分析各個棧上出現的方法的次數

優點:性能高
缺點: 不適合做精確的分析
適用範圍:尋找程序的執行熱點,cpu密集型

指令插入:使用增強的技術修改java class的字節碼,在函數的出入口增加埋點

優點:數據準確
缺點:導致jvm內聯優化失效,性能低
適用範圍:分析具體耗時路徑的各個執行時間,io密集型

一般先使用抽樣在定位到大致的範圍,然後使用指令插入分析具體代碼執行路徑中的耗時,jprofile可以通過過濾只對指定類進行增強

  1. Thread Status:選擇線程統計狀態,Runnable显示的是cpu時間,不包含sleep這種時間一般都是這個模式。還可以使用IO Net模式分析io等待,Wait分析鎖競爭模式
  2. Call tree filters :調用樹過濾:用於過濾不需要的類,例如你使用web框架,棧中起始的方法都是框架中的代碼,最後才是你的業務代碼,這時候可以使用Call tree filters來過濾不需要的類型,減少統計造成的性能開銷

內存剖析

分析內存泄漏的利器,主要是看內存中內存佔比和大對象。很多時候如果有內存泄漏基本都是以為某些類型的對象佔用了大頭。

arthas (類似btrace的工具)

Arthas 是Alibaba開源的Java診斷工具。線上debug的工具,很多時候因為性能和安全等原因我們不能直接遠程調試線上的jvm,這時候我們可以使用arthas來查看內存的數據,方法調用情況,打印日誌信息等。

比較常用的:

  1. watch 看方法調用情況 -c 統計周期,默認值為120秒
  2. monitor 統計方法調用信息
  3. getstatic 查看靜態變量
  4. logger 查看和修改logger
  5. trace 方法內部調用路徑,並輸出方法路徑上的每個節點上耗時

示例:

  1. monitor -c 5 com.miaozhen.bazaro.deal.PreferredDealFilterService filter
  2. watch com.miaozhen.bazaro.share.manager.util.DealManager getDspToDealsByPid "returnObj"

gceasy

https://gceasy.io/ 一個在線分析gc日誌的網站,

四、實際案例

連接泄漏

場景描述:我們公司的用戶服務對接了第三方騰訊雲通信服務,在用戶註冊的時候我們需要走http接口調騰訊雲,問題就出在http連接那塊,同事當時採用了,線上出現了cpu100%的問題,日誌出現java.lang.OutOfMemoryError: GC overhead limit exceeded。

排查思路:這個其實很好定位,本來還想打印線程棧看下到底是哪個導致的cpu100%,一看日誌直接定位到gc出問題。GC overhead limit exceeded是指gc佔用了大量的cpu時間又回收不了內存引起的,從內存泄露去考慮,重啟服務 ,啟動參數加上-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./user.hprof -verbose:gc -Xloggc:user%t.log。問題復現的時候獲得了堆的dump文件,然後通過Jprofile分析,發現有大量的http.HttpKeepAliveCache實例,佔用了80%的內存,大致定位到是由於http連接泄露。同事封裝的HttpUtil中使用了HttpsURLConnection,在讀取完數據的時候沒有關閉InputStream導致連接沒有關閉。

說明:GC overhead limit exceeded,默認情況下,如果Java進程花費98%以上的時間執行GC,並且每次只有不到2%的堆被恢復,則JVM拋出此錯誤。這個錯誤是parallel Scavenge 特有的

String拼接導致內存溢出

公司的後台有段時間會間歇性的卡頓,嚴重的情況下會導致cpu100%。在cpu100%的時候,通過top定位到進程號,然後輸入H切換到線程,記住具體的進程號,使用jstack打印java進程的線程棧,jstack輸出為十六進制,需要將top的轉換成十六進制的然後入找線程經常卡在哪個方法。定位到方法發現是查詢用戶關聯設備號的方法出問題,方法的邏輯是從數據庫查詢設備號,在內存中以以逗號分隔拼接返回,如1,2,3。這個bug的原因是有如下:

sql出錯,導致查詢返回數據量很多,正常情況最多幾百個,但是異常情況有七萬個設備號
字符串拼接採用str+=”1234″的形式,導致大量的內存分配和回收。
運營在點擊後台查詢的時候發現沒返回,點掉就重新點,導致服務器多個線程卡在這個方法造成cpu100%。解決完sql,改用StringBuilder問題解決。

堆內存佔用過大

我們的一個服務程序,老年代設置了10g,新生代2g,偶會會出現內存溢出的線程,通過分析內存發現deal數據佔用了大量內存,最高可達9.4g。

堆數據:

問題代碼:

優化后堆數據:

優化后降低了老年代改為4g,大大降低了Jvm的堆的大小,16g機器現在可部署兩個實例,且Full Gc穩定在一天一次,Young Gc 5s一次,均處正常。

CPU佔用高問題

最近在分析拍賣程序時,發現com.miaozhen.bazaro.deal.PreferredDealFilterService#filter方法佔用了90%的cpu時間。

cpu熱點圖:

問題代碼:

分析該方法的時長:

查看耗時deal數據

aerospike線程阻塞導致內存溢出問題

問題:拍賣在五點多收到網站推送數據的時候發生OOM。

查看日誌發現,有很多關於線程阻塞的報錯,是讀取aerospike卡住導致。報錯如下:

觀察gc分析結果:

可以看到本來堆內存始終穩定在一個水平,在一個時間點之後,堆內存開始穩步上漲,十分符合內存泄漏的特徵。

觀察堆內存數據:

注:這個堆內存不是當時,當時的堆內存沒找到,佔比是類似的。這個圖內存優化之後的,所以老年代只有4g。

可以看到其中OrderedExecutor佔用了大量的內存,這個數據接口是用來存放http請求的接口。

總結:

晚上九點40線程阻塞,但是請求的任務不停地往他的tasks裏面放,十分鐘后grafana監控显示上升了16%的超時率(六個verticle掛了一個),從4%到20%。
查看內存監控圖,9點40開始內存上升,不再回收,最終存了2900萬個tasks,一個線程佔用了10g內存,到晚上11.15左右日誌出現大量的空指針和超時,十分鐘后監控圖显示全部超時,gc監控显示大量full gc,因為內存不夠大量的gc佔用了進程cpu時間。,5點多的時候推送物料,服務器內存溢出。

參考資料:

問題

  1. 什麼樣的代碼算是耗時的代碼,或者說耗時代碼的特徵是什麼
  2. jvm一個線程發生OOM會導致JVM掛掉嗎
  3. 內存問題會導致cpu飆高嗎

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

納智捷LUXGEN推電動車版S3房車

納智捷(LUXGEN)全力搶攻小車市場,在2015台北國際新車大展上以「智能與電能」為主題,正式推出電動車S3 EV+,造型與汽油版的S3 Turbo大致相同。同時展出的還有S5、U7、U6、M7 TURBO ERO HYPER與V7 TURBO等車款。

在十位LUXGEN Girls「十全十美」的陣容下,納智捷在台北新車大展舉行之前預先舉辦展示活動。LUXGEN將成立科技互動體驗區,帶領參展民眾親身體驗虛擬實境的感受。

S3 EV+ 本次首度亮相,以LUXGEN旗下最小型的房車S3為設計藍本。LUXGEN先前已透露2016年第二季將推出首款小型入門車S3 Turbo,搭配1.5升直列四缸全鋁合金汽油引擎、日本Aisin六速手自排變速箱,油耗最低可達每公升行駛17公里。S3 EV+ 之造型與S3 Turbo相似,但具體規格還未公告。

今年的台北新車大展將於12月25日於台北世貿一館舉行。

(照片來源:LUXGEN)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

Java nio 空輪詢bug到底是什麼

編者注:Java nio 空輪詢bug也就是Java nio在Linux系統下的epoll空輪詢問題。

epoll機制是Linux下一種高效的IO復用方式,相較於select和poll機制來說。其高效的原因是將基於事件的fd放到內核中來完成,在內核中基於紅黑樹+鏈表數據結構來實現,鏈表存放有事件發生的fd集合,然後在調用epoll_wait時返回給應用程序,由應用程序來處理這些fd事件。

使用IO復用,Linux下一般默認就是epoll,Java NIO在Linux下默認也是epoll機制,但是JDK中epoll的實現卻是有漏洞的,其中最有名的java nio epoll bug就是即使是關注的select輪詢事件返回數量為0,NIO照樣不斷的從select本應該阻塞的Selector.select()/Selector.select(timeout)中wake up出來,導致CPU 100%問題。如下圖所示:

那麼產生這個問題的原因是什麼的?其實在 上已經說明的很清楚了,比如下面是bug復現的一個場景:

A DESCRIPTION OF THE PROBLEM :
The NIO selector wakes up infinitely in this situation..
0. server waits for connection
1. client connects and write message
2. server accepts and register OP_READ
3. server reads message and remove OP_READ from interest op set
4. client close the connection
5. server write message (without any reading.. surely OP_READ is not set)
6. server's select wakes up infinitely with return value 0

上面的場景描述的問題就是連接出現了RST,因為poll和epoll對於突然中斷的連接socket會對返回的eventSet事件集合置為POLLHUP或者POLLERR,eventSet事件集合發生了變化,這就導致Selector會被喚醒,進而導致CPU 100%問題。根本原因就是JDK沒有處理好這種情況,比如SelectionKey中就沒定義有異常事件的類型。

class SelectionKey {
    public static final int OP_READ = 1 << 0;
    public static final int OP_WRITE = 1 << 2;
    public static final int OP_CONNECT = 1 << 3;
    public static final int OP_ACCEPT = 1 << 4;
}

既然nio epoll bug存在,那麼能不能規避呢?答案是有的,比如netty就很巧妙的規避了這個問題,它的處理機制就是如果發生了這種情況,並且發生次數超過了SELECTOR_AUTO_REBUILD_THRESHOLD(默認512),則調用rebuildSelector()進行Selecttor重建,這樣就不用管之前發生了異常情況的那個連接了。因為重建也是根據SelectionKey事件對應的連接來重新註冊的。

該問題最早在 Java 6 發現,隨後很多版本聲稱解決了該問題,但實際上只是降低了該 bug 的出現頻率,目前從網上搜索到的資料显示,Java 8 還是存在該問題()。

最後一起來分析下,nio epoll bug不是linux epoll的問題,而是JDK自己實現epoll時沒有考慮這種情況,或者說因為其他系統不存在這個問題,Java為了封裝(比如SelectionKey 中的4個事件類型)的統一而沒去處理?

這裏思考下,如果想要從java nio層面上來解決這個問題,該如何做呢?

一種是nio事件類型SelectionKey新加一種”錯誤”類型,比如針對linux epoll中的epollhup和epollerr,如果出現這種事件,建議程序直接close socket,但這種方式相對來說對於目前的nio SelectionKey改動有點大,因為SelectionKey的定義目前是針對所有jdk平台的;還有一種是針對jdk nio 對epoll的封裝中,對於epoll的epollhup和epollerr事件,epoll封裝內部直接處理,比如close socket,但是這種方案也有一點尷尬的是,可能上層應用代碼還保留有出現問題的socket引用,這時最好是應用程序能夠感知這種情況來處理比較好。

Java nio空轉問題由來已久,一般程序中是通過新建Selector的方式來屏蔽掉了JDK5/6的這個問題,因此,對於開發者來講,還是盡量將JDK的版本更新到最新,或者使用NIO框架如Netty,Grizzly等進行研發,以免出更多的問題。

推薦閱讀

歡迎小夥伴關注【TopCoder】閱讀更多精彩好文。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

第六屆中國國際新能源汽車論壇2016打造行業規模最大,最國際化的新能源汽車論壇

2016年4月20-22日∣中國•上海

誰能智造未來-技術應用與新熱點

隨著全球能源危機的加重及汽車排放引起的環境問題日益得到世界各國的重視,發展環保節能的汽車已經成為全球汽車行業的必然趨勢。

在過去五屆新能源汽車論壇成功舉辦的基礎上,由希邁商務諮詢(上海)有限公司主辦的2016年第六屆中國國際新能源汽車論壇即將於4月20日-4月22日在上海隆重舉行。新能源汽車系列論壇成功邀請了包括國家發改委能源研究所、世界電動車協會、亞太電動車協會、世界氫能協會、世界分散式能源聯盟、中國工程院等在內的政府單位與研究機構,以及包括寶馬、賓士、奇瑞捷豹路虎、大眾、奧迪、比亞迪、上汽、北汽等在內的知名整車商,共同研討新能源汽車行業政策趨勢、技術路線及難點、基礎設施建設、商業模式等並取得了豐碩的成果,獲得了業內外人士的一致好評。

在即將到來的2016年,組委會為感謝業內外人士對系列論壇長期以來的支援和關注,將傾情奉上相比歷屆舉辦規模最大的第六屆新能源汽車論壇,涉及三個考察活動,主論壇及三個分論壇。屆時將誠邀全球範圍內的整車製造商、電網電力公司、電池廠商、零部件供應商、核心技術提供商和政府官員近500位行業人士一起,對新能源汽車產業面臨的挑戰,機遇與對策各方面進行為期三天更深層次並具有建設和戰略性的探討。

部份往屆演講嘉賓

會議亮點

豐富的內容:
8大板塊的深度解析

參會嘉賓:
500+高度滿意的企業決策者,120+業內知名企業,30+國家和地區

參會嘉賓分析:
17%+來自各國政府部門及權威機構,25%+來自知名整車商

演講嘉賓:
40+世界新能源汽車行業知名發言嘉賓

交流機會:
16+小時的交流機會:圓桌討論、VIP午宴和開放式問答

會議形式:
1個主論壇,1個晚宴,3個分論壇以及一天3個考察活動

會議結構

若您對峰會有更多要求,請撥打021-6045 1760與我們聯繫,謝謝理解和支持!
我們期待與貴單位一起出席於2016年4月20-22日在上海舉辦的第六屆中國國際新能源汽車論壇2016,以利決策!
想瞭解詳細內容,請登陸官方網站:
連絡人:Hill ZENG(曾先生)
電話:0086 21-6045 1760
傳真:0086 21-6047 5887
郵箱:

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

氫燃料電池車軍事價值高,美國陸軍與雪佛蘭聯手測試

氫燃料電池車往往主打排放的廢氣中只有水,無一般內燃機引擎汽車的碳氫化合物、氮氧化物等等有害人體的空氣污染,不過,沒有引擎聲響,又會排出水,讓氫燃料電池車更適用於軍事用途,美國陸軍就看上了這點,與通用汽車(GM)聯手,以通用旗下雪佛蘭(Chevrolet)科羅拉多(Colorado)中型貨卡車改裝測試氫燃料電池車的軍事用途。

美國陸軍坦克車輛研發工程中心(Tank Automotive Research, Development and Engineering Center,TARDEC)表示,氫燃料電池車因為沒有引擎而相當安靜,而不論是斥侯、特戰部隊及其他專業軍種,都很重視行動匿蹤匿聲,更重要的一點是,氫燃料電池車產生的廢棄物是純水,在軍事行動中,往往需經過缺乏水源的區域,車輛自己就會產水,對在嚴峻環境執行任務有莫大幫助。   此外,氫燃料電池車可產生強大扭力,也適合在越野環境下執行任務。同時,燃料電池不僅能驅動車輛,還能同時充當其他攜帶式電子作戰裝置的電源,士兵們就不用在攜帶燃料的同時還要另外攜帶電池。   TARDEC 打算與通用汽車合作,測試一輛改裝為氫燃料電池為動力總成的雪佛蘭科羅拉多中型貨卡車,進行 12 個月的極端軍事測試,考驗它是否能勝任嚴酷的軍事需求。但 TARDEC 不願透露將如何測試車輛的詳細過程。   日本政府與豐田汽車正全力推廣氫燃料電池車,不過目前商用市場上仍有相當多障礙,如今無聲又會產水的特性先被美國陸軍看上,或許氫燃料電池會先從軍事用途發展也說不定。

(首圖來源:) 

(本文授權轉載自《》─〈〉)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

Gogoro 將不再受限充電站,GoCharger 讓騎士在家在商店都可充

曾在 2015 年 CES 展中展出新一代電動車的 Gogoro 於 2016 年再度參加美國 CES 消費電子大展,除了分享 Smartscooter 智慧雙輪的佈建經驗、展示全新智慧功能外,並發表了 GoCharger 智慧電池座,讓個人或商店也可以提供設置充電座,讓 Gogoro 不再受限於現有的充電站,擴大 Gogoro 的行駛區域。

Gogoro 執行長暨共同創辦人陸學森表示:「自從上市以來我們持續聆聽消費者的聲音,並在去(2015)年七月承諾開發個人充電設備,很高興在此向大家正式介紹 GoCharger 智慧電池座。在不久的將來,車主可以到餐廳或商店,一面用餐購物、一面使用 GoCharger 智慧電池座為 Gogoro 電池充電,讓人車都獲得能源補給再前往下一個目的地。」

GoCharger 輕鬆設置在家中或商店內,只要將兩顆 Gogoro 電池置入電池槽,電池座即會透過無線網路連結 Gogoro 能源網路雲端系統進行電池認證,除了車主可以透過 Gogoro App 頁面查看充電狀況之外,Gogoro 亦可於遠端進行電量管理、控制充電速度與觀察電池健康狀態。GoCharger 智慧電池座將提供「快充」與「標準」兩個版本,預計最快將於 2016 年下半年正式上市。

陸學森也進一步表示,「為讓更多城市有機會參與 Gogoro 能源網路的推廣計畫,我們也宣布正式啟動 Gogoro OPEN 共享計劃,邀請全球消費者與商家上網申請設置 GoCharger 智慧電池座,反應最熱烈的地方就有可能成為 Gogoro 進駐的下一個城市。」

結合手機即可無鑰上鎖開啟車廂   除分享 GoCharger 智慧電池座與 Gogoro OPEN 能源網路共享計劃外,執行長陸學森也表示智慧型手機已成為消費者生活中不可或缺的工具,因此 Gogoro也希望結合更多手機應用、持續優化車主的騎乘體驗,因為推出了最新的智慧解鎖功能,只要透過智慧型手機(iOS/Android)或是 Apple Watch ,車主不需鑰匙即可上鎖、解鎖智慧雙輪與開啟後車廂。

  這個新功能未來會預先安裝於接下來新型式年份的 Gogoro 電動機車上,而 Gogoro 也將為所有車主提供免費軟硬體升級,並於近期公佈車主回廠進行更新的流程,該原有的車主也可以體驗到此一功能。  
2015 年 12 月份銷售翻倍,台北市佔率達 10.8%   發表新功能之外,Gogoro 也公布了相關銷售成績,目前雖然僅於大台北、桃園與新竹地區販售,在 12 月整體機車市場僅微幅成長 2% 的情況下,Gogoro 創造銷售成長 210% 、掛牌數達到 1,528 台,除穩坐電動機車市場龍頭寶座,更較第二名全國掛牌總數多出近 900 輛。   在上述區域的商用和自用電動機車市場中,每四台新車就有三台是 Smartscooter 智慧雙輪,若單看自用市場則是十台新車有超過九台是智慧雙輪,佔比高達 91%,數據顯示 Gogoro 在上一波的售價調整下已達到成效,大幅提升消費者的接受度。   目前在雙北與桃竹地區,Gogoro 於機車整體市場佔有率為 8.3%,台北市更是首度超過一成達到市佔率 10.8% 的成績。現今全台已有近四千台的智慧雙輪在道路上奔馳,接下來除配合便利商店與其他地區的擴展外,再加上新的 GoCharger 不再受限於現有充電站下與以及 Gogoro OPEN 的計劃執行,應可再拉升原本還在猶豫的消費者選擇。   (本文授權轉載自《》─〈〉)  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

對於計算機相關專業我們在迷茫什麼

計算機相關專業初識–對於計算機相關專業我們在迷茫什麼

前言

由於種種原因,迫使我寫下這篇博客,我相信,初入計算機相關專業的萌新肯定很迷茫,我該學什麼,我該如何去學,我該如何學好等等問題纏繞心頭。有很多學弟學妹問我該如何去學計算機相關專業,作為過來人,我決定將我的所知所得寫下來,讓初入計算機相關專業的萌新的學習之路走得更順暢一些。

一、什麼是計算機

對於剛學習計算機相關專業的萌新來說,了解一下計算機的工作原理是十分必要的,但是在這裏我們不過多闡述,讓大家簡單了解一下就好。

讓我們先來看一下對於計算機名詞的解釋:

計算機(computer)俗稱電腦,是現代一種用於高速計算的电子計算機器,可以進行數值計算,又可以進行邏輯計算,還具有存儲記憶功能。是能夠按照程序運行,自動、高速處理海量數據的現代化智能电子設備。

划重點:

  • 我們注意到,計算機就是一種用於進行數值計算的現代化智能电子設備。需要理解的是為什麼是進行數值計算,在這裏,你會疑惑,為什麼是數值計算呢,我輸入的明明不是数字呀?這個問題很容易解釋清楚,因為計算機只是一種电子設備,它不具有人類獨立思考和不斷學習的能力,它的所有功能都是事先設定好的,所以當計算機面對輸入字符的時候,會將它統一按照ASCII(計算機編碼系統)規則轉換為數值“0”和“1”(二進制數值),所以,在計算機里,數據存儲都是用“0”和“1”(即二進制數值)來實現。

  • 還有一點值得注意,按照程序運行,那麼問題來了,程序是什麼?程序就是一組計算機能識別和執行的指令, 它以某些程序設計語言編寫,運行於某種目標結構體繫上 。舉個例子,程序就像是用英語(程序設計語言,例如c,c++)寫的文章,要讓一個懂的英語的人(編譯器,如C的編譯器gcc,這裏要注意編譯器和IDE的區別,通常IDE包含編譯器)同時也會閱讀這篇文章的人(結構體系)來閱讀、理解、標記這篇文章。

有學妹問過我,為什麼簡單的代碼,能實現豐富的效果。其實這取決於編譯器的強大能力。下面來簡單介紹一下,編輯器,編譯器,IDE(集成開發環境)的區別。

  • 編輯器:編輯器就是用來編輯的軟件,比如windows自帶的記事本就是一個編輯器, 記事本沒有語法高亮,不显示行號,當一段可執行代碼寫完后無法通過內置環境執行,必須手動輸入命令執行編譯等等一些弊端,所以很少有程序員會用記事本去寫代碼 , 寫代碼比較好用的編輯器軟件有vscode,vim,sublime,notepad++,emacs,atom等等 ,雖然編輯器原始功能不足,但是開發人員為了使編輯器更加友好,所以有很多內置插件可供使用,完全可以手動打造一個IDE。
  • 編譯器:簡單來說,編譯器就是將“一種語言(一般為高級語言,如c,c++,java,python等,計算機不可直接識別和執行)”翻譯為“另一種語言(一般為低級語言,低級語言即機器語言,機器語言是用二進制代碼錶示的計算機能直接識別和執行的一種機器指令的集合)”的程序。舉個例子,用Dev-C++寫好一段可執行"hello,world!"C語言代碼之後,我們要讓它在屏幕打印出來我們想要它輸出的"hello,world!",就需要通過gcc編譯器執行編譯后才能显示。其他語言同理。
  • IDE:集成開發環境,用於程序開發環境的應用程序,一般包含代碼編輯器、編譯器、調試器、圖像用戶界面等工具。集成了代碼編寫、程序分析、程序編譯、程序調試等功能。如 jetbrains 的用於Java開發的 IntelliJ IDEA 、用於JavaScript開發的WebStorm、用於Python開發Pycharm,微軟的 Visual Studio系列 ,IBM的Eclipse。

二、我們該學什麼

很多初入計算機相關專業的萌新,總是很迷茫,不知道自己該學什麼,通常是他們知道如何去學好學校開設的每一門課程,就是不知道自己該向哪些方向學習,這些方向指的是專業技能和就業方向,諸如web開發、Android/IOS開發、數據分析、人工智能、網絡安全、遊戲開發、軟件測試等等。有這種疑惑很正常,迷茫也是正常的,但我們總要讓自己了解自己所需,然後腳踏實地,一步一步去充實自己的能力。而我想做的也很簡單,就是幫助大家解除心裏的疑惑。那麼,我們開始進入正題。

1. 我們該如何選擇適合自己的方向

對於這個問題,其實是很難回答清楚的,因為每個人的興趣都不相同,所以就很難去站在自己的角度去回答疑問者的問題。但是,原理都是想通的,我相信我的經驗會幫助到你們。

  • 通常,學校每學期都會開設一門或多門語言(程序設計語言,下文同),那麼,喜歡一門語言,首先要愛上它的語言風格,諸如Java的嚴謹,Python的自由,總有一款適合你;其次,在學習語言的過程中,一定要了解它能幹什麼,市場環境如何,工作崗位多少等綜合因素,再決定要不要去深入這門語言,並且主攻自己感興趣的那個方向。

  • 對於學校沒有開設,但是自己又想學習的語言而言,該如何去選擇。首先,學校開設的語言基本是市場比較流行的語言,也符合市場需求,所以,完全可以在學校開設的語言中去選擇自己想要了解並學習的語言。此外,我們可以藉助 TIOBE ( TIOBE 編程社區指數是編程語言流行度的指標,該榜單每月更新一次,指數基於全球技術工程師、課程和第三方供應商的數量。包括流行的搜索引擎,如谷歌、必應、雅虎、維基百科、亞馬遜、YouTube 和百度都用於指數計算。 )去了解語言的流行程度,流行程度決定市場需求,以此來參考自己想要了解並學習的語言,在此附上2019年11月語言排名。

2. 主流編程語言主要應用場景

  • Java

    1. 企業級應用開發: 大到全國聯網的系統,小到中小企業的應用解決方案,Java都佔有極為重要的地位 。
    2. web後端開發: JSP+Servlet+JavaBean 是一種比較流行的開發模式。
    3. 移動領域:手機遊戲。
    4. Android App開發: android 開發只用到了JAVA的語法和JAVA SE的一小部分API。
  • C

    C語言是一門基礎語言,是其他一些語言的基礎,例如MATLAB,Object-C,Lua等.同時也是學習來比較難的語言,達到精通的程度沒有3-10年左右很難,C語言沒有比較完善的開發框架,是面向過程的一門語言,講究算法跟邏輯。

    1. 科研
    2. 服務器: 網絡核心設備,如路由器、交換機、防火牆。
    3. 操作系統:類unix系統(Linux/freebsd)
    4. 嵌入式開發: 在一個特定的硬件環境上開發與構建特定的可編程軟件系統的綜合技術。
    5. 自動化控制
  • Python

    1. 圖形處理
    2. 數學處理
    3. 文本處理
    4. 數據庫編程
    5. 網絡編程
    6. 多媒體應用
    7. pymo引擎: 運行於Symbian S60V3,Symbian S60V5,Symbian 3,Android,Windows,Linux,Mac Os,Maemo,MeeGo系統上的AVG遊戲引擎。
    8. 黑客編程
    9. 網絡安全
  • C++

    1. 遊戲開發
    2. 科學計算
    3. 網絡軟件
    4. 操作系統
    5. 設備驅動程序
    6. 移動設備
    7. 嵌入式開發
    8. 科研
    9. 編譯器
  • C#

    1. web後端開發
    2. 桌面軟件開發
    3. 人工智能
    4. 遊戲開發
  • JavaScript
    唯一能用於前後端開發的語言web前端開發
    1. web前端開發
    2. node web後端開發
    3. 操作系統
    4. 後台
    5. 桌面軟件開發
    6. 混合App
    7. 小程序
  • PHP

    1. web後端開發
    2. 桌面軟件開發
    3. 命令行腳本
  • SQL

    1. 操作數據庫
  • Swift

    1. 蘋果生態系統應用開發
  • Ruby

    1. web開發
  • R

    數據科學闖天下,左手Python右手R

    1. 機器學習
    2. 數據分析
    3. 科學計算
  • Go

    1. web後端開發
    2. 高性能服務器應用

3. 主流編程語言學習路徑(將持續更新,僅供參考)

  • JavaScript

4. 主流編程語言入門學習書籍推薦

語言 書籍
C 《嗨翻C語言》
C++ 《C++權威教程》
Java 《Java輕鬆學》
Python 《Python編程從入門到實戰》
JavaScript 《JavaScript入門經典》
PHP 《PHP編程實戰》
SQL 《SQL基礎教程》
Swift 《Swift編程權威指南》
Ruby 《Ruby從入門到精通》
R 《R語言實戰》
Go 《Go語言聖經》

5. 編程學習網站推薦

網站 網址
菜鳥教程
W3School
實驗樓
猿學
慕課網
SegmentFault
博客園
GitHub
掘金
學習數據科學
易百教程
看雲

三、總結

通篇寫完,感覺自己也重新學到了很多,學習就是一個反覆複習的過程,每次學習都能帶給自己不一樣的收穫。希望以上內容可以給初入計算機相關專業的萌新帶來一些幫助,後面我會不斷更新和優化本文,請大家持續關注。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

改善空氣污染問題 米蘭禁汽車入市區

摘錄自2020年2月3日星島日報報導

意大利北部米蘭市2日採取應付空氣污染的措施,由上午10時起至黃昏禁止汽車駛入市區,藉以減少霧霾,但有許多駕駛人士不理會。警方在不足三小時內,發出了162張罰款告票。
  
截至當地時間中午12時半,警方人員截查了621名駕駛者,並發出了162張告票。每名違例者會被罰款164歐羅。
  
這項禁令不適用於電動車及殘疾人士駕駛的汽車。期間,部分市中心街道維持開放讓汽車進出,包括通往球會AC米蘭主球場的道路。今次已不是米蘭第一次採取這種措施,但不是所有市民都歡迎。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享