JVM難學?那是因為你沒認真看完這篇文章

来源:https://www.cnblogs.com/AIPAOJIAO/archive/2018/07/29/9387802.html
-Advertisement-
Play Games

一:虛擬機記憶體圖解 JAVA程式運行與虛擬機之上,運行時需要記憶體空間。虛擬機執行JAVA程式的過程中會把它管理的記憶體劃分為不同的數據區域方便管理。 虛擬機管理記憶體數據區域劃分如下圖: 數據區域分類: 方法區 (Method Area) 虛擬機棧 (VM Stack) 本地方法棧 (Native Me ...


一:虛擬機記憶體圖解

JAVA程式運行與虛擬機之上,運行時需要記憶體空間。虛擬機執行JAVA程式的過程中會把它管理的記憶體劃分為不同的數據區域方便管理。

虛擬機管理記憶體數據區域劃分如下圖:

數據區域分類:

方法區            (Method Area)

虛擬機棧         (VM Stack)

本地方法棧     (Native Method Stack)

堆                   (Heap)

程式計數器    (Program Counter Register)

直接記憶體        (Direct Memory)

說明:

1. 程式計數器

行號指示器,位元組碼指令的分支、迴圈、跳轉、異常處理、線程恢復(CPU切換),每條線程都需要一個獨立的計數器,線程私有記憶體互不影響,該區域不會發生記憶體溢出異常。


2. 虛擬機棧

是線程私有的,聲明周期與線程相同,虛擬機棧是Java方法執行的記憶體模型,每個方法被執行時都會創建一個棧幀,即方法運行期間的基礎數據結構,棧幀用於存儲:局部變數表、操作數棧、動態鏈接、方法出口等,每個方法執行中都對應虛擬機棧幀從入棧到處棧的過程。

是一種數據結構,是虛擬機中的局部變數表,對應物理層之上的程式數據模型。

局部變數表,是一種程式運行數據模型,存放了編譯期可知的各種數據類型例如:

Boolean、byte、char、short、int、float、long、double、對象引用類型(對象記憶體地址變數,指針或句柄),程式運行時,根據局部變數表分配棧幀空間大小,在運行中,大小是不變的異常類型:stackOverFlowError 線程請求棧深度大於虛擬機允許深度 OutOfMemory 記憶體空間耗盡無法進行擴展。


3. 本地方法棧

與虛擬機棧類似,虛擬機棧為Java程式服務,本地方法棧支持虛擬機的運行服務,具體實現由虛擬機廠商決定,也會拋出 stackOverFlowError、OutOfMemory異常。


4. 堆

是虛擬機管理記憶體中最大的一部分,被所有線程共用,用於存放對象實例(對象、數組),物理上不連續的記憶體空間,由於GC收集器,分代收集,所以劃分為:新生代 Eden、From SurVivor空間、To SurVivor空間,allot buffer(分配空間),可能會劃分出多個線程私有的緩衝區,老年代。


5. 方法區

與堆一樣屬於線程共用的記憶體區域,用於存儲虛擬機載入的類信息、常量、靜態變數、即時編譯器編譯後的代碼(動態載入OSGI)等數據。理論上屬於java虛擬機的一部分,為了區分開來叫做 Non-Heap非堆。

這個區域可以選擇不進行垃圾回收,該區域回收目的主要是常量池的回收,及類型的卸載class,記憶體區不足時會拋出OutOfMemory異常

運行時常量池:

方法區的一部分,Class的版本、欄位、介面、方法等,及編譯期生成的各種字面量、符號引用,編譯類載入後存放在該區域。會拋出OutOfMemory異常。


6. 直接記憶體

直接記憶體不屬於虛擬記憶體區域,是一種基於通道與緩衝區的IO方式,可以使用本地函數直接分配堆外記憶體,在堆中存儲引用的外部記憶體地址,通過引用完成對直接引用記憶體的操作,1.4之後提供的NIO顯著提高效率,避免了堆記憶體與Native記憶體的來回覆制操作,不受虛擬機記憶體控制,會拋出OUtOfMemory異常。


二:對象訪問內部實現過程

對象訪問 涉及到對象的地址變更狀態變更,記憶體地址移動,變數、介面、實現類、方法、父類型等。

 一、 句柄方式 (訪問)

二、指針方式 (訪問)

優缺點:

句柄訪問方式:reference中存儲的是穩定的地址,對象變更時只會改變句柄實例數據指針,引用本身不需要修改

指針訪問方式:優點速度快,節省了指針定位時間開銷


三:記憶體區域控制參數及對應溢出異常

開發過程中,或程式運行過程中每次遇到OutOfMemory異常或GC異常或StackOverflowError異常我們都是一堆參數亂配,都把值調大,只是大體知道是跟jvm記憶體分配有關,具體應該怎麼調,對應的異常應該調整那些參數,或者換句話說,jvm記憶體分配區域中都分別對應那些參數大多數情況下都是不知道的,只是把相關的參數跳上去,預期結果都是應該起作用,到底能不能起作用,自己心裡也沒底。下麵就來說一下jvm堆、棧、方法區等記憶體區域對應的參數,及每個區域可能拋出的異常類型,發生異常的場景分析。


一、參數類型

 1.堆空間參數

2.棧空間參數

3.方法區空間參數

4.本機直接記憶體參數

 


二、異常類型

1.OutOfMemory異常

2.StackOverflowError異常


三、輔助參數說明

1.-XX:+HeapDumpOnOutOfMemoryError 列印堆記憶體異常時列印出快照信息

2.-XX:+HeapDumpPath 快照輸出路徑

3.-Xmn指定eden區的大小 -XX:SurvirorRation來調整幸存區的大小

4.-XX:PretenureSizeThreshold設置進入老年代的閥值


四、參數說明、對應場景的異常

1.堆記憶體參數

-Xms:堆最小值(新生代和老年代之和)

-Xmx:堆最大值(新生代和老年代之和)

當最小值=最大值時,這時堆記憶體是不可擴展的。

例:-Xms80M -Xmx80M 

通常將-Xmx和-Xms設置為一樣的大小來減少gc的次數,堆記憶體不足時拋出OutOfMemoryError異常。


2.棧記憶體參數

-Xss

例:-Xss128k

單線程下無論棧幀太大還是棧容量太小,及引用深度超過虛擬機允許深度都會拋出StackOverflowError每個方法壓入棧的幀大小是不一致的。多線程下當每個線程分配棧幀太大記憶體不能夠擴展時拋出OutOfMemoryError異常線程棧幀越大,可創建的線程越少。


3.方法區參數

-XX:PermSize方法區記憶體最小值

-XX:MaxPermSize 方法區記憶體最大值

各個線程共用的記憶體區域,主要用來存儲類的元數據、常量、靜態變數、即時編譯器編譯後的代碼等數據

例:-XX:PermSize=20M -XX:MaxPermSize=20M

異常類型 OutOfMemoryError :

原因:常量過多,或代理反射等使用頻繁


4.本機直接記憶體參數

-XX:MaxDirectMemorySize

例:-XX:MaxDirectMemorySize=10M

不足時拋出OutOfMemory異常


四:垃圾收集演算法

經典的垃圾回收演算法以下幾種

 一、標記--清除演算法(Mark-Sweep)

回收前狀態:

回收後狀態:

 

優缺點:

演算法執行分為兩個階段標記與清除,所有的回收演算法,基本都

基於標記回收演算法做了深度優化

缺點:效率問題,記憶體空間碎片(不連續的空間)


二、複製演算法(Copying)

回收前狀態:

Eden記憶體空間 8

Survivor1空間(From空間)1

 

Survivor2空間(To空間) 1

Eden記憶體空間與Survivor空間 8:1

 

回收後狀態:

Survivor1空間(From空間)1

 

Eden記憶體空間與Survivor空間 8:1

優缺點:

比較標記清除演算法,避免了回收造成的記憶體碎片問題,

缺點:以局部的記憶體空間犧牲為代價,不過空間的浪費比較小,預設8:1的比例1是浪費的。

複製也有一定的效率與空間成本


三、標記整理演算法(Mark-Compact)

回收前狀態:

回收後狀態:

 

優缺點:

避免了,空間的浪費,與記憶體碎片問題。

缺點:整理時複製有效率成本。


五:垃圾收集器

一、七種垃圾收集器

(1) Serial(串列GC)-XX:+UseSerialGC

(2) ParNew(並行GC)-XX:+UseParNewGC

(3) Parallel Scavenge(並行回收GC)

(4) Serial Old(MSC)(串列GC)-XX:+UseSerialGC

(5) CMS(併發GC)-XX:+UseConcMarkSweepGC

(6) Parallel Old(並行GC)-XX:+UseParallelOldGC

(7) G1(JDK1.7update14才可以正式商用)

二.1~3用於年輕代垃圾回收:年輕代的垃圾回收稱為minor GC

三.4~6用於年老代垃圾回收(當然也可以用於方法區的回收):年老代的垃圾回收稱為full GC

G1獨立完成"分代垃圾回收"

註意:並行與併發

並行:多條垃圾回收線程同時操作

併發:垃圾回收線程與用戶線程一起操作


四、常用五種組合

Serial/Serial Old

ParNew/Serial Old:與上邊相比,只是比年輕代多了多線程垃圾回收而已

ParNew/CMS:當下比較高效的組合

Parallel Scavenge/Parallel Old:自動管理的組合

G1:最先進的收集器,但是需要JDK1.7update14以上


五. Serial/Serial Old

年輕代Serial收集器採用單個GC線程實現"複製"演算法(包括掃描、複製)

年老代Serial Old收集器採用單個GC線程實現"標記-整理"演算法

Serial與Serial Old都會暫停所有用戶線程(即STW)

說明:

STW(stop the world):編譯代碼時為每一個方法註入safepoint(方法中迴圈結束的點、方法執行結束的點),在暫停應用時,需要等待所有的用戶線程進入safepoint,之後暫停所有線程,然後進行垃圾回收。

適用場合:

CPU核數<2,物理記憶體<2G的機器(簡單來講,單CPU,新生代空間較小且對STW時間要求不高的情況下使用)

-XX:UseSerialGC:強制使用該GC組合

-XX:PrintGCApplicationStoppedTime:查看STW時間


六.ParNew/Serial Old:

ParNew除了採用多GC線程來實現複製演算法以外,其他都與Serial一樣,但是此組合中的Serial Old又是一個單GC線程,所以該組合是一個比較尷尬的組合,在單CPU情況下沒有Serial/Serial Old速度快(因為ParNew多線程需要切換),在多CPU情況下又沒有之後的三種組合快(因為Serial Old是單GC線程),所以使用其實不多。

-XX:ParallelGCThreads:指定ParNew GC線程的數量,預設與CPU核數相同,該參數在於CMS GC組合時,也可能會用到


七.Parallel Scavenge/Parallel Old:

特點:

年輕代Parallel Scavenge收集器採用多個GC線程實現"複製"演算法(包括掃描、複製)年老代Parallel Old收集器採用多個GC線程實現"標記-整理"算ParallelScavenge與Parallel Old都會暫停所有用戶線程(即STW)

說明:

吞吐量:CPU運行代碼時間/(CPU運行代碼時間+GC時間)CMS主要註重STW的縮短(該時間越短,用戶體驗越好,所以主要用於處理很多的交互任務的情況)Parallel Scavenge/Parallel Old主要註重吞吐量(吞吐量越大,說明CPU利用率越高,所以主要用於處理很多的CPU計算任務而用戶交互任務較少的情況)

參數設置:

-XX:+UseParallelOldGC:使用該GC組合

-XX:GCTimeRatio:直接設置吞吐量大小,假設設為19,則允許的最大GC時間占總時間的1/(1+19),預設值為99,即1/(1+99)

-XX:MaxGCPauseMillis:最大GC停頓時間,該參數並非越小越好

-XX:+UseAdaptiveSizePolicy:開啟該參數,-Xmn/-XX:SurvivorRatio/-XX:PretenureSizeThreshold這些參數就不起作用了,虛擬機會自動收集監控信息,動態調整這些參數以提供最合適的的停頓時間或者最大的吞吐量(GC自適應調節策略),而我們需要設置的就是-Xmx,-XX:+UseParallelOldGC或-XX:GCTimeRatio兩個參數就好(當然-Xms也指定上與-Xmx相同就好)

註意:

-XX:GCTimeRatio和-XX:MaxGCPauseMillis設置一個就好

不開啟-XX:+UseAdaptiveSizePolicy,-Xmn/-XX:SurvivorRatio/-XX:PretenureSizeThreshold這些參數依舊可以配置,以resin伺服器為例

<jvm-arg>-Xms2048m</jvm-arg> <jvm-arg>-Xmx2048m</jvm-arg> <jvm-arg>-Xmn512m</jvm-arg> <jvm-arg>-Xss1m</jvm-arg> <jvm-arg>-XX:PermSize=256M</jvm-arg> <jvm-arg>-XX:MaxPermSize=256M</jvm-arg> <jvm-arg>-XX:SurvivorRatio=8</jvm-arg> <jvm-arg>-XX:MaxTenuringThreshold=15</jvm-arg> <jvm-arg>-XX:+UseParallelOldGC</jvm-arg> <jvm-arg>-XX:GCTimeRatio=19</jvm-arg> <jvm-arg>-XX:+PrintGCDetails</jvm-arg> <jvm-arg>-XX:+PrintGCTimeStamps</jvm-arg> View Code

適用場合:

很多的CPU計算任務而用戶交互任務較少的情況不想自己去過多的關註GC參數,想讓虛擬機自己進行調優工作


八、調優方法

8.1 新對象預留新生代

由於fullGC(老年代)的成本遠比minorGC(新生代和老年代)的成本大,所以給應用分配一個合理的新生代空間,儘量將對象分配到新生代減小fullGC的頻率

8.2 大對象進入老年代

將大對象直接分配到老年代,保持新生代對象的結構的完整性,以提高GC效率, 以通過-XX:PretenureSizeThreshold設置進入老年代的閥值

8.3 穩定與震蕩的堆大小

穩定的對大小是對垃圾回收有利的,方法將-Xms和-Xmx的大小一致

8.4 吞吐量優先

儘可能減少系統執行垃圾回收的總時間,故採用並行垃圾回收器

-XX:+UseParallelGC或使用-XX:+UseParallelOldGC

8.5 降低停頓

使用CMS回收器,同時減少fullGC的次數


九、獲取gc信息的方法

9.1 -verbose:gc或者-XX:+PrintGC  獲取gc信息

9.2 -XX:+PrintGCDetails  獲取更加詳細的gc信息

9.3 -XX:+PrintGCTimeStamps  獲取GC的頻率和間隔

9.4 -XX:+PrintHeapAtGC  獲取堆的使用情況

9.5 -Xloggc:D:\gc.log  指定日誌情況的保存路徑


十、jvm調優實戰-tomcat啟動加速

在tomcat的bin/catalina.bat文件的開頭添加相關的配置


六:監控工具

監控工具:一般問題定位,性能調優都會使用到。

(一)、jps

Jps是參照Unix系統的取名規則命名的,而他的功能和ps的功能類似,可以列舉正在運行的餓虛擬機進程並顯示虛擬機執行的主類以及這些進程的唯一ID(LVMID,對應本機來說和PID相同),他的用法如下:

Jps [option] [hostid]

jps -q 只輸出LVMID

jps -m 輸出JVM啟動時傳給主類的方法

jps -l 輸出主類的全名,如果是Jar則輸出jar的路徑

jps -v 輸出JVM的啟動參數


(二)、jstat 

 jstat主要用於監控虛擬機的各種運行狀態信息,如類的裝載、記憶體、垃圾回收、JIT編譯器等,在沒有GUI的伺服器上,這款工具是首選的一款監控工具。其用法如下:

jstat [option vmid [interval [s|ms] [vount] ] ]

jstat 監控內容 線程好 刷新時間間隔 次數

jstat –gc 20445 1 20    :監視Java堆,包含eden、2個survivor區、old區和永久帶區域的容量、已用空間、GC時間合計等信息

jstat –gcutil 20445 1 20:監視內容與-gc相同,但輸出主要關註已使用空間占總空間的百分比

jstat –class 20445 1 20:監視類的裝載、卸載數量以及類的裝載總空間和耗費時間等

.......-gccapcity......:監視內容與-gc相同,但輸出主要關註Java區域用到的最大和最小空間

.......-gccause........:與-gcutil輸出信息相同,額外輸出導致上次GC產生的原因

.......-gcnew..........:監控新生代的GC情況

.......-gcnewcapacity..:與-gcnew監控信息相同,輸出主要關註使用到的最大和最小空間

.......-gcold..........:監控老生代的GC情況

.......-gcoldcapacity..:與-gcold監控信息相同,輸出主要關註使用到的最大和最小空間

.......-gcpermcapacity.:輸出永久帶用到的最大和最小空間

.......-compiler.......:輸出JIT編譯器編譯過的方法、耗時信息

.......-printcompilation:輸出已經被JIT編譯的方法


(三)、jinfo

jinfo的作用是實時查看虛擬機的各項參數信息jps –v可以查看虛擬機在啟動時被顯式指定的參數信息,但是如果你想知道預設的一些參數信息呢?除了去查詢對應的資料以外,jinfo就顯得很重要了。jinfo的用法如下:

Jinfo [option] pid

(四)、jmap

map用於生成堆快照(heapdump)。當然我們有很多方法可以取到對應的dump信息,如我們通過JVM啟動時加入啟動參數 –XX:HeapDumpOnOutOfMemoryError參數,可以讓JVM在出現記憶體溢出錯誤的時候自動生成dump文件,亦可以通過-XX:HeapDumpOnCtrlBreak參數,在運行時使用ctrl+break按鍵生成dump文件,當然我們也可以使用kill -3 pid的方式去恐嚇JVM生成dump文件。Jmap的作用不僅僅是為了獲取dump文件,還可以用於查詢finalize執行隊列、Java堆和永久帶的詳細信息,如空間使用率、垃圾回收器等。其運行格式如下:

Jmap [option] vmip

監控堆棧信息主要用來定位問題的原因,生成堆棧快照

.......-dump......:生成對應的dump信息,用法為-dump:[live,]format=b,file={fileName}

.......-finalizerinfo......:顯示在F-Queue中等待的Finalizer方法的對象(只在linux下生效)

.......-heap......:顯示堆的詳細信息、垃圾回收器信息、參數配置、分代詳情等

.......-histo......:顯示堆棧中的對象的統計信息,包含類、實例數量和合計容量

.......-permstat......:以ClassLoder為統計口徑顯示永久帶的記憶體狀態

.......-F......:虛擬機對-dump無響應時可使用這個選項強制生成dump快照

例子:jmap -dump:format=b,file=yhj.dump 20445


(五)、jstack

Jstack用於JVM當前時刻的線程快照,又稱threaddump文件,它是JVM當前每一條線程正在執行的堆棧信息的集合。生成線程快照的主要目的是為了定位線程出現長時間停頓的原因,如線程死鎖、死迴圈、請求外部時長過長導致線程停頓的原因。通過jstack我們就可以知道哪些進程在後臺做些什麼?在等待什麼資源等!其運行格式如下:

Jstack [option] vmid

-F 當正常輸出的請求不響應時強制輸出線程堆棧

-l 除堆棧信息外,顯示關於鎖的附加信息

-m 顯示native方法的堆棧信息


(六)、jconsole

在JDK的bin目錄下,監控記憶體,thread,堆棧等


(七)、jprofile

類似於jconsole,比jconsole監控信息更全面,記憶體,線程,包,cup 類,堆棧,等等 


 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 條件變數同步 有一類線程需要滿足條件之後才能夠繼續執行,Python提供了threading.Condition 對象用於條件變數線程的支持,它除了能提供RLock()或Lock()的方法外,還提供了 wait()、notify()、notifyAll()方法。 lock_con=threading ...
  • 所需環境: 1. IDEA UItimate 2. JDK 3. Maven 創建工程 一開始創建一個普通的maven項目即可, 下麵展示最終完成的工程目錄,其中創建res文件夾以及放入testNG.xml文件的步驟後面會提到: 在pom中添加依賴: 創建package 與測試類 HelloTest ...
  • 列表(list):列表是有序的,且可以修改 說明:列表裡面可以存放:數字、字元串、列表、布爾值,可以嵌套任意類型 列表存放元素的原理:通過鏈表的方式 1.創建列表:通過list(列表)類,創建了一個test_list的對象 test_list=["Tom","Mary","Jim","Disk"] ...
  • 給定一組(串)數據,根據輸入得號碼,查詢歸屬地 如有錯誤,感謝指正! ...
  • Exchanger應該算併發包中工具使用相對少的,因為它主要用於線程之間交換數據,它的用法比較簡單在不同線程之間使用exchange方法交換數據,但是內部實現比較巧妙,使用了unsafe的CAS原子操作、自旋來解決衝突問題,下麵我們通過源碼一探究竟。 ...
  • 前言 Mybatis的緩存主要有兩種: 系統緩存,也就是我們一級緩存與二級緩存; 自定義的緩存,比如Redis、Enhance等,需要額外的單獨配置與實現,具體日後主要學習介紹。 在這裡主要記錄系統緩存的一些簡單概念, 並沒有涉及原理。其中會涉及Mybatis的相關配置以及生命周期等。 主要參考資料 ...
  • Java高級編程 掌握 類的定義; 對象的定義; 類的構造方法; 方法的重載 實現步驟: 新建Worker類 為Worker類添加四個屬性 為Worker類添加帶參的構造方法,不帶參的構造方法不再自動創建 創建不帶參數的構造方法 為Worker類添加getTax()方法 為Worker類添加getS ...
  • 題意 板子題,題意很清楚吧。。 Sol 很顯然可以直接上LCT。。 但是這題允許離線,於是就有了一個非常巧妙的離線的做法,好像叫什麼線段樹分治?? 此題中每條邊出現的位置都可以看做是一段區間。 我們用線段樹維護。線段樹的每個節點維護一個vector表示覆蓋了當前節點的邊的存在區間 因為總的邊數是$M ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...