對JVM還有什麼不懂的?資深架構師一篇文章帶你深入淺出JVM!
本文跟大家聊聊JVM的內部結構,從元件中的多執行緒處理,JVM系統執行緒,區域性變數陣列等方面進行解析
JVM
JVM = 類載入器(classloader) + 執行引擎(execution engine) + 執行時資料區域(runtime data area)
下面這幅圖展示了一個典型的JVM(符合JVM Specification Java SE 7 Edition)所具備的關鍵內部元件。
元件中的多執行緒處理
多執行緒處理”或“自由執行緒處理”指的是一個程式同時執行多個操作執行緒的能力。 作為多執行緒應用程式的一個示例,某個程式在一個執行緒上接收使用者輸入,在另一個執行緒上執行多種複雜的計算,並在第三個執行緒上更新資料庫。 在單執行緒應用程式中,使用者可能會花費時間等待計算或資料庫更新完成。 而在多執行緒應用程式中,這些程序可以在後臺進行,因此不會浪費使用者時間。 多執行緒處理可以是元件程式設計中的一個非常強大的工具。通過編寫多執行緒元件,您可以建立在後臺執行復雜計算的元件,它們允許使用者介面 (UI) 在計算的過程中自由地響應使用者輸入。 雖然多執行緒處理是一個強大的工具,但是要將其正確應用卻比較困難。 未能正確實現的多執行緒程式碼可能降低應用程式效能,或甚至導致應用程式凍結。 下列主題將向您介紹多執行緒程式設計的一些注意事項和最佳做法。.NET Framework 提供幾個在元件中進行多執行緒處理的選項。 System.Threading 名稱空間中的功能是一個選項。 基於事件的非同步模式是另一個選項。 BackgroundWorker 元件是對非同步模式的實現;它提供封裝在元件中以便於使用的高階功能。
JVM記憶體管理機制
(1)記憶體區域與記憶體溢位異常
(2)垃圾收集器與記憶體分配策略
(3)虛擬機器效能監控與故障處理工具
JVM調優
1.JVM執行子系統
(1)類檔案結構
(2)類載入機制
(3)位元組碼執行引擎
2.程式編譯與程式碼優化
(1)編譯期優化
(2)執行期優化
3.實戰調優案例與解決方法
JVM系統執行緒
如果你用jconsole或者任何其他的debug工具檢視,可能會看到有許多執行緒在後臺執行。這些執行著的後臺執行緒不包含主執行緒,主執行緒是基於執行publicstatic void main(String[]) 的需要而被建立的。而這些後臺執行緒都是被主執行緒所建立。在HotspotJVM中主要的後臺系統執行緒,見下表:
單個執行緒
每個執行緒的一次執行都包含如下的元件
程式計數器(PC)
除非當前指令或者操作碼是原生的,否則當前指令或操作碼的地址都需要依賴於PC來定址。如果當前方法是原生的,那麼該PC即為undefined。所有的CPU都有一個PC,通常PC在每個指令執行後被增加以指向即將執行的下一條指令的地址。JVM使用PC來跟蹤正在執行的指令的位置。事實上,PC被用來指向methodarea的一個記憶體地址。
原生棧
不是所有的JVM都支援原生方法,但那些支援該特性的JVM通常會對每個執行緒建立一個原生方法棧。如果對JVM的JNI(JavaNative Invocation)採用c連結模型的實現,那麼原生棧也將是一個C實現的棧。在這個例子中,原生棧中引數的順序 、返回值都將跟通常的C程式相同。一個原生方法通常會對JVM產生一個回撥(這依賴於JVM的實現)並執行一個Java方法。這樣一個原生到Java的呼叫發生在棧上(通常在Java棧),與此同時執行緒也將離開原生棧,通常在Java棧上建立一個新的frame。
棧
每個執行緒都有屬於它自己的棧,用於儲存線上程上執行的每個方法的frame。棧是一個後進先出的資料結構,這可以使得當前正在執行的方法位於棧的頂部。對於每個方法的執行,都會有一個新的frame被建立並被入棧到棧的頂部。當方法正常的返回或在方法執行的過程中遇到未捕獲的異常時frame會被出棧。棧不會被直接進行操作,除了push/ pop frame 物件。因此可以看出,frame物件可能會被分配在堆上,並且記憶體也沒必要是連續的地址空間(請注意區分frame的指標跟frame物件)。
棧的限制
一個棧可以是動態的或者是有合適大小的。如果一個執行緒要求更大的棧,那麼將丟擲StackOverflowError異常;如果一個執行緒要求新建立一個frame,又沒有足夠的記憶體空間來分配,將會丟擲OutOfMemoryError異常。
Frame
對於每一個方法的執行,一個新frame會被建立並被入棧到棧頂。當方法正常返回或在方法執行的過程中遇到未捕獲的異常,frame會被出棧。
區域性變數陣列
區域性變數陣列包含了在方法執行期間所用到的所有的變數。包含一個對this的引用,所有的方法引數,以及其他區域性定義的變數。對於類方法(比如靜態方法),方法引數的儲存索引從0開始;而對於例項方法,索引為0的槽都為儲存this指標而保留。
運算元棧
運算元棧在位元組碼指令被執行的過程中使用。它跟原生CPU使用的通用目的的暫存器類似。大部分的位元組碼都把時間花費在跟運算元棧打交道上,通過入棧、出棧、複製、交換或者執行那些生產/消費值的操作。對位元組碼而言,那些在區域性變數陣列和運算元棧之間移動值的指令是非常頻繁的。
動態連結
每個frame都包含一個對執行時常量池的引用。該引用指向將要被執行的方法所屬的類的常量池。該引用也用於輔助動態連結。
當一個Java類被編譯時,所有對儲存在類的常量池中的變數以及方法的引用都被當做符號引用。一個符號引用僅僅只是一個邏輯引用而不是最終指向實體記憶體地址的引用。JVM的實現可以選擇解析符號引用的時機,該時機可以發生在當類檔案被驗證後、被載入後,這稱之eager或靜態分析;不同的是它也可以發生在當符號引用被首次使用的時候,稱之為lazy或延遲分析。但JVM必須保證:解析發生在每個引用被首次使用前,同時在該時間點,如果遇到分析錯誤能夠丟擲異常。繫結是一個處理過程,它將被符號引用標識的欄位、方法或類替換為一個直接引用。這個處理過程只發生一次,因為符號引用需要被完全替換。如果一個符號引用關聯著一個類,而該類還沒有被解析,那麼該類也會被立即載入。每個直接引用都被以偏移的方式儲存,該儲存結構關聯著變數或方法的執行時位置。
執行緒之間共享
堆
堆中某個節點的值總是不大於或不小於其父節點的值;
堆總是一棵完全二叉樹。
將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。常見的堆有二叉堆、斐波那契堆等。
堆的定義如下:n個元素的序列{k1,k2,ki,…,kn}當且僅當滿足下關係時,稱之為堆。
(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)
若將和此次序列對應的一維陣列(即以一維陣列作此序列的儲存結構)看成是一個完全二叉樹,則堆的含義表明,完全二叉樹中所有非終端結點的值均不大於(或不小於)其左、右孩子結點的值。由此,若序列{k1,k2,…,kn}是堆,則堆頂元素(或完全二叉樹的根)必為序列中n個元素的最小值(或最大值)
非堆式記憶體
有些物件並不會建立在堆中,這些物件在邏輯上被認為是JVM機制的一部分。
非堆式的記憶體包括:
永久代中包含:
方法區
內部字串
程式碼快取:用於編譯以及儲存方法,這些方法已經被JIT編譯成原生代碼
記憶體管理
物件和陣列永遠都不會被顯式釋放,因此只能依靠垃圾回收器來自動地回收它們。
通常,以如下的步驟進行:
新物件和陣列被建立在年輕代
次垃圾回收器將在年輕代上執行。那些仍然存活著的物件,將被從eden區移動到survivor區
主垃圾回收器將會把物件在代與代之間進行移動,主垃圾回收器通常會導致應用程式的執行緒暫停。那些仍然存活著的物件將被從年輕代移動到老年代
永久代會在每次老年代被回收的時候同時進行,它們在兩者中其一滿了之後都會被回收
JIT編譯
JIT具體的做法是這樣的:當載入一個型別時,CLR為該型別建立一個內部資料結構和相應的函式,當函式第一被呼叫時,JIT將該函式編譯成機器語言.當再次遇到該函式時則直接從cache中執行已編譯好的機器語言.
方法區
所有的執行緒共享相同的方法區。所以,對於方法區資料的訪問以及對動態連結的處理必須是執行緒安全的。如果兩個執行緒企圖訪問一個還沒有被載入的類(該類必須只能被載入一次)的欄位或者方法,直到該類被載入完成,這兩個執行緒才能繼續執行。
類的檔案結構
一個被編譯過的類檔案包含如下的結構:
ClassFile { u4magic; u2minor_version; u2major_version; u2constant_pool_count; cp_infocontant_pool[constant_pool_count – 1]; u2access_flags; u2this_class; u2super_class; u2interfaces_count; u2interfaces[interfaces_count]; u2fields_count; field_infofields[fields_count]; u2methods_count; method_infomethods[methods_count]; u2attributes_count; attribute_infoattributes[attributes_count];}
可以使用javap命令檢視被編譯後的java類的位元組碼。
下面列出了在該類檔案中,使用到的操作碼:
就像在其他通用的位元組碼中那樣,以上這些操作碼主要用於跟本地變數、運算元棧以及執行時常量池打交道。
構造器有兩個指令,第一個將“this”壓入到運算元棧,接下來該構造器的父構造器被執行,這一操作將導致this被“消費”,因此this將從運算元棧出棧。
而對於sayHello()方法,它的執行將更為複雜。因為它不得不通過執行時常量池,解析符號引用到真實的引用。第一個運算元getstatic,用來入棧一個指向System類的靜態欄位out的引用到運算元棧。接下來的運算元ldc,入棧一個字串字面量“Hello”到運算元棧。最後,invokevirtual運算元,執行System.out的println方法,這將使得“Hello”作為一個引數從運算元棧出棧,併為當前執行緒建立一個新的frame。
類載入器
JVM的啟動是通過bootstrap類載入器來載入一個用於初始化的類。在publicstatic void main(String[])被執行前,該類會被連結以及例項化。main方法的執行,將順序經歷載入,連結,以及對額外必要的類跟介面的初始化。
載入: 載入是這樣一個過程:查詢表示該類或介面型別的類檔案,並把它讀到一個位元組陣列中。接著,這些位元組會被解析以確認它們是否表示一個Class物件以及是否有正確的主、次版本號。任何被當做直接superclass的類或介面也一同被載入。一旦這些工作完成,一個類或介面物件將會從二進位制表示中建立。
連結: 連結包含了對該類或介面的驗證,準備型別以及該類的直接父類跟父介面。簡而言之,連結包含三個步驟:驗證、準備以及解析(optional)
驗證:該階段會確認類以及介面的表示形式在結構上的正確性,同時滿足Java程式語言以及JVM語義上的要求。
在驗證階段執行這些檢查意味著在執行時可以免去在連結階段進行這些動作,雖然拖慢了類的載入速度,然而它避免了在執行位元組碼的時候執行這些檢查。
準備:包含了對靜態儲存的記憶體分配以及JVM所使用的任何資料結構(比如方法表)。靜態欄位都被建立以及例項化為它們的預設值。然而,沒有任何例項化器或程式碼在這個階段被執行,因為這些任務將會發生在例項化階段。
解析:是一個可選的階段。該階段通過載入引用的類或介面來檢查符號引用是否正確。如果在這個點這些檢查沒發生,那麼對符號引用的解析會被推遲到直到它們被位元組碼指令使用之前。
例項化 類或介面,包含執行類或介面的例項化方法:<clinit>
在JVM中存在多個不同職責的類載入器。每一個類載入器都代理其已被載入的父載入器(除了bootstrap類載入器,因為它是根載入器)。
Bootstrap類載入器:當java程式執行時,java虛擬機器需要裝載java類,這個過程需要一個類裝載器來完成。而類裝載器本身也是一個java類,這就出現了類似人類的第一位母親是如何產生出來的問題。
其實,java虛擬機器中內嵌了一個稱為Bootstrap的類裝載器,它是用特定於作業系統的原生代碼實現的,屬於java虛擬機器的核心,這個Bootstrap類裝載器不用專門的類裝載器去裝載。Bootstrap類裝載器負責載入java核心包中的類。
Extension 類載入器:從標準的Java擴充套件API中載入類。例如,安全的擴充套件功能集。
System 類載入器:這是應用程式預設的類載入器。它從classpath中載入應用程式類。
使用者定義的類載入器:可以額外得定義類載入器來載入應用程式類。使用者定義的類載入器可用於一些特殊的場景,比如:在執行時重新載入類或將一些特殊的類隔離為多個不同的分組(通常web伺服器中都會有這樣的需求,比如Tomcat)。
更快的類載入
一個稱之為類資料共享(CDS)的特性自HotspotJVM 5.0開始被引進。在安裝JVM期間,安裝器載入一系列的Java核心類(如rt.jar)到一個經過對映過的記憶體區進行共享存檔。CDS減少了載入這些類的時間從而提升了JVM的啟動速度,同時允許這些類在不同的JVM例項之間共享。這大大減少了記憶體碎片。
方法區的位置
JVM Specification Java SE 7 Edition清楚地宣告:儘管方法區是堆的一個邏輯組成部分,但最簡單的實現可能是既不對它進行垃圾回收也不壓縮它。然而矛盾的是利用jconsole檢視Oracle的JVM的方法區(以及CodeCache)是非堆形式的。OpenJDK程式碼顯示CodeCache相對ObjectHeap而言是VM中一個獨立的域。
類載入器引用
類通常是按需載入,即第一次使用該類時才載入。由於有了類載入器,Java執行時系統不需要知道檔案與檔案系統。
執行時常量池
JVM對每個型別維護著一個常量池,它是一個跟符號表相似的執行時資料結構,但它包含了更多的資料。Java的位元組碼需要一些資料,通常這些資料會因為太大而難以直接儲存在位元組碼中。取而代之的一種做法是將其儲存在常量池中,位元組碼包含一個對常量池的引用。執行時常量池主要用來進行動態連結。
幾種型別的資料會儲存在常量池中,它們是:
數值字面量
字串字面量
類的引用
欄位的引用
方法的引用
如果你編譯下面的這個簡單的類:
package org.jvminternals;public class SimpleClass { public void sayHello() {System.out.println("Hello");}}
生成的類檔案的常量池,看起來會像下圖所示:
Constant pool: #1 = Methodref #6.#17 // java/lang/Object."<init>":()V#2 = Fieldref #18.#19 // java/lang/System.out:Ljava/io/PrintStream;#3 = String #20 // "Hello"#4 = Methodref #21.#22 // java/io/PrintStream.println:(Ljava/lang/String;)V#5 = Class #23 // org/jvminternals/SimpleClass#6 = Class #24 // java/lang/Object#7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Lorg/jvminternals/SimpleClass; #14 = Utf8 sayHello #15 = Utf8 SourceFile #16 = Utf8 SimpleClass.java #17 = NameAndType #7:#8 // "<init>":()V#18 = Class #25 // java/lang/System#19 = NameAndType #26:#27 // out:Ljava/io/PrintStream;#20 = Utf8 Hello #21 = Class #28 // java/io/PrintStream#22 = NameAndType #29:#30 // println:(Ljava/lang/String;)V#23 = Utf8 org/jvminternals/SimpleClass #24 = Utf8 java/lang/Object#25 = Utf8 java/lang/System #26 = Utf8 out#27 = Utf8 Ljava/io/PrintStream; #28 = Utf8 java/io/PrintStream #29 = Utf8 println #30 = Utf8 (Ljava/lang/String;)V
常量池中包含了下面的這些型別:
異常表
異常表儲存了每個異常處理器的資訊:
起始點
終止點
處理程式碼的PC偏移量
被捕獲的異常類的常量池索引
如果一個方法定義了try-catch或try-finally異常處理器,那麼一個異常表將會被建立。它包含了每個異常處理器的資訊或者finally塊以及正在被處理的異常型別跟處理器程式碼的位置。
當一個異常被丟擲,JVM會為當前方法尋找一個匹配的處理器。如果沒有找到,那麼該方法最終會唐突地出棧當前stackframe而異常會被重新丟擲到呼叫鏈(新的frame)。如果在所有的frame都出棧之前還是沒有找到異常處理器,那麼當前執行緒將會被終止。當然這也可能會導致JVM被終止,如果異常被丟擲到最後一個非後臺執行緒的話,比如該執行緒就是主執行緒。
最終異常處理器會匹配所有的異常型別並且無論什麼時候該型別的異常被丟擲總是會得到執行。在沒有異常丟擲的例子中,finally塊仍然會在方法的最後被執行。一旦return語句被執行就會立即跳轉到finally程式碼塊繼續執行。
字元比較
字元比較(character comparison)是指按照字典次序對單個字元或字串進行比較大小的操作,一般都是以ASCII碼值的大小作為字元比較的標準。
符號表
符號表在編譯程式工作的過程中需要不斷收集、記錄和使用源程式中一些語法符號的型別和特徵等相關資訊。這些資訊一般以表格形式儲存於系統中。如常數表、變數名錶、陣列名錶、過程名錶、標號表等等,統稱為符號表。對於符號表組織、構造和管理方法的好壞會直接影響編譯系統的執行效率。
在JVM中,內部字串被儲存在字串表中。字串表是一個hashtable對映物件指標到符號(比如:Hashtable<oop,Symbol>),它被儲存在永久代裡。
相關推薦
對JVM還有什麼不懂的?資深架構師一篇文章帶你深入淺出JVM!
本文跟大家聊聊JVM的內部結構,從元件中的多執行緒處理,JVM系統執行緒,區域性變數陣列等方面進行解析 JVM JVM = 類載入器(classloader) + 執行引擎(execution engine) + 執行時資料區域(runtime data area) 下面這幅圖展示了一個典
一篇文章帶你搞懂JS對象的自我銷毀
log 還要 很快 實例化 webp dom操作 angular listener css 在日常的JS組件開發中,往往會有一些較為復雜的DOM操作及事件監聽,尤其是在處理UI層面的widgets時候更為明顯。常常會花很多精力在對象的init上,而當組件需要被移除時則僅僅是
一篇文章帶你讀懂JSP的使用的理解
JSP語言是幹嘛的呢?一句話:就是在html中編寫java程式碼。能夠直接在頁面中執行並編譯,能夠訪問已經存在的類介面等,在jsp中的java與你在後臺寫的java功能一樣。相比servlet中,我們響應請求時,需要把大量的html寫在方法裡,很繁瑣。jsp就能夠在html中寫java。但是兩者貌似
一篇文章帶你看懂AWS re:Invent 2018大會,揭祕Amazon Aurora
本文由雲+社群發表 | 本文作者: 劉峰,騰訊雲NewSQL資料庫產品負責人。曾職於聯想研究院,Teradata北京研發中心,從事資料庫相關工作8年。2017年加入騰訊資料庫產品中心,擔任NewSQL資料庫產品負責人。 雲資料庫與傳統資料庫的戰爭已打響,一個字概括就是“搶”。 如火如茶的 AWS re
一篇文章帶你看懂AWS re:Invent 2018大會,揭秘Amazon Aurora
2018年 保健 god 發揮 監控服務 insight 遊戲機 pci 雲計算 本文由雲+社區發表 | 本文作者: 劉峰,騰訊雲NewSQL數據庫產品負責人。曾職於聯想研究院,Teradata北京研發中心,從事數據庫相關工作8年。2017年加入騰訊數據庫產品中心,擔任Ne
無線充電技術究竟有何神祕之處?一篇文章帶你讀懂什麼是無線充電技術
無線充電技術這個概念在很早之前就已經被提出了,發展至今在電子領域已經被深入研究應用,雖然還未曾大範圍普及,但在消費電子領域的發展已經取得不錯的成績。手機廠商也紛紛在自家旗艦機上加入這一革新性的先進充電技術。那麼什麼是無線充電技術,往下看便知曉,一篇文章帶你讀懂無線充電技術。 充電運用了一
一篇文章帶你快速理解微服務架構,由淺入深帶你走進微服務架構的核心
首先微服務並沒有一個官方的定義,想要直接描述微服務比較困難,我們可以通過對比傳統WEB應用,來理解什麼是微服務。 傳統的WEB應用核心分為業務邏輯、介面卡以及API或通過UI訪問的WEB介面。業務邏輯定義業務流程、業務規則以及領域實體。介面卡包括資料庫訪問元件、訊息元件以及訪
一篇文章帶你弄懂大資料!
一、大資料是什麼? 大資料,big data,《大資料》一書對大資料這麼定義,大資料是指不能用隨機分析法(抽樣調查)這樣捷徑,而採用所有資料進行分析處理。 這句話至少傳遞兩種資訊: 1、大資料是海量的資料 2、大資料處理無捷徑,對分析處理技術提出了更高的要求 歡迎加入大資料交流群:65855854
一篇文章帶你弄懂大數據!
次數 進行 的區別 任務管理 ase 快速 運算 環境 哪些 一、大數據是什麽? 大數據,big data,《大數據》一書對大數據這麽定義,大數據是指不能用隨機分析法(抽樣調查)這樣捷徑,而采用所有數據進行分析處理。 這句話至少傳遞兩種信息: 1、大數據是海量的數據 2、大
一篇文章帶你讀懂雲端計算(轉)
艾瑞諮詢11-02 導語:雲端計算是一種模型,它可以實現隨時隨地、便捷地、隨需應變地從可配置計算資源共享池中獲取所需的資源(例如網路、伺服器、儲存、應用及服務),資源能夠快速供應並釋放,使管理資源的工作量和與服務提供商的互動減小到最低限度。 亞馬遜AWS、微軟Azure、阿里Aliyun組成的3A團
長見識了: 一篇文章帶你看懂 硬碟資料恢復軟體的原理
有用過資料恢復軟體的小夥伴都知道,硬碟或者儲存卡里面不小心刪除或者格式化的檔案都是有機會找回來的。大家知不知道這是個什麼原理呢? 不管是我們的硬碟、U盤還是儲存卡,其實都是相當於一個倉庫。我們需要什麼東西就去倉庫裡面拿,或者把東西存到倉庫裡面。比如說我們要在硬盤裡面存一部
一篇文章帶你弄懂BI和大資料!
BI(Business Intelligence),中文翻譯是商務智慧,是一套完整的解決方案,用來將組織中現有的資料進行有效的整合,快速準確的提供報表並提出決策依據,幫助組織做出明智的業務經營決策。 商業智慧能夠輔助的業務經營決策,既可以是操作層的,也可以是戰術層和戰略層的決策。為了將
精辟:一篇文章帶你看懂數據儲存!
安全問題 mark cap 伸縮 雲盤 增長 租戶 影響 圖片 前言:日益火熱的雲服務 小米組織架構調整上了熱搜,如同阿裏巴巴、華為和騰訊一樣,小米組織架構調整中也將雲平臺單獨成為一個部門。自2018年以來,各大企業調整組織架構的動作中,其實可以窺見大企業對雲平臺的重視程度
一篇文章帶你瞭解 ZooKeeper 架構
上一篇文章,我們講解了 ZooKeeper 入門知識,這篇文章主要講解下 ZooKeeper 的架構,理解 ZooKeeper 的架構可以幫助我們更好地設計協同服務。 首先我們來看下 ZooKeeper 的總體架構圖。 ZooKeeper 總體架構 應用使用 ZooKeeper 客戶端庫來使用 ZooKe
五分鐘學Java:一篇文章帶你搞懂spring全家桶套餐
原創宣告 本文首發於微信公眾號【程式設計師黃小斜】 本文作者:黃小斜 轉載請務必在文章開頭註明出處和作者。 本文思維導圖 什麼是Spring,為什麼你要學習spring? 你第一次接觸spring框架是在什麼時候?相信很多人和我一樣,第一次瞭解spring都不是做專案的時候用到,而是在網上看到或者是聽到過
還不知道事務訊息嗎?這篇文章帶你全面掃盲!
在分散式系統中,為了保證資料一致性是必須使用分散式事務。分散式事務實現方式就很多種,今天主要介紹一下使用 RocketMQ 事務訊息,實現分佈事務。 > 文末有彩蛋,看完再走 ## 為什麼需要事務訊息? 很多同學可能不知道事務訊息是什麼,沒關係,舉一個真實業務場景,先來帶你瞭解一下普通的訊息存在問題。
一篇文章讓你豁然開朗,成為架構師你必須了解的一些疑問
有一點 同事 繼續 模式 常見 瓶頸 功能實現 很多 獨立 前言:我先介紹一下我的新同事,公司好多同事都這麽叫他James,有10年開發經驗的架構師,之前在人人網待過,之後我們也聊了很多。 在聊天過程中,我們也聊到了他為什麽離開人人網,也聊到了他在成為架構師的道路上的辛酸歷
一篇文章讓你豁然開朗,成為架構師你必須瞭解的一些疑問
前言: 我先介紹一下我的新同事,公司好多同事都這麼叫他James,有10年開發經驗的架構師,之前在人人網待過,之後我們也聊了很多。 在聊天過程中,我們也聊到了他為什麼離開人人網,也聊到了他在成為架構師的道路上的辛酸歷程,聊過後,才發現,離開人人網的原因和他的架構師之路和我
還在害怕學不會Python嘛?這篇文章讓你瞬間讀懂Python入門!
零基礎學習Python能學會嗎?這個問題幾乎是所有初學Python的小白都會問到的問題。其實Python是非常適合初學者入門的,相較於其他主流類程式語言,Python具有更好的可讀性,因此上手更容易,而且即便你是零基礎也一樣能學會。 獻給Python初學者,零基礎學習Python能學會嗎?
架構師負責訂規範,你負責執行!
心意相通的研發之間,本不需要BB這BB那搞些約束。但寧教我心徒枉然,不教銀光惹塵埃。過分的放縱愛自由,那就是一去不復返了。 本文系稍成點系統的碎碎語,如有共鳴,拍掌,麼! 為什麼要有規範 規範是一種束縛,是騰飛前的最後一步加速。大公司免費開源複雜的軟體,有一個非常重要的目的就是想要佔據特殊解決方案的標準