当前位置:网站首页>卷起來,突破35歲焦慮,動畫演示CPU記錄函數調用過程
卷起來,突破35歲焦慮,動畫演示CPU記錄函數調用過程
2022-07-05 09:45:00 【hi-dhl】
hi 大家好,我是 DHL。公眾號:ByteCode ,專注分享有趣硬核原創內容,Kotlin、Jetpack、性能優化、系統源碼、算法及數據結構、動畫、大廠面經
全文分為 視頻版 和 文字版,
視頻版:
通過語音和動畫,能够更加直觀的看到,內存記錄方法調用和返回過程。
文字版
我們在寫代碼的時候有沒有思考過 方法如何調用 、 方法執行完之後如何返回 、 內存如何記錄方法調用過程 。而這也是今天這篇文章重點內容。
方法調用和返回過程涉及到了,虛擬機棧、程序計數器、局部變量錶、操作數棧、方法返回地址、動態鏈接等等內容,涉及到知識點很多,同時這些內容也是高頻面試題,所以我將拆分成多篇文章,針對每個知識點去做詳細的分析。而今天這篇文章我們重點去看內存是如何記錄方法調用和返回過程。
虛擬機棧
Java 方法以棧幀的形式,運行在虛擬機棧(Java 棧)中,棧是線程私有的,程序啟動的時候,會創建一個 main 線程,操作系統會為每一個線程分配一段內存,線程創建的時候會創建一個虛擬機棧,虛擬機棧的生命周期和線程一樣,線程結束了,虛擬機棧也銷毀了。
每個 Java 方法,對應一個個棧幀,所以方法開始和結束,都是一個個棧幀入棧和出棧的過程,效果如下圖所示。
棧幀
每個 Java 方法,都是一個個棧幀,每個棧幀包括了:局部變量錶、操作數棧、方法返回地址、動態鏈接、附加信息。
- 局部變量錶: 保存方法參數列錶和方法內的局部變量,按照聲明的順序存儲,它以數組的形式展示,如果是實例方法,索引為 0 是 this 的引用,如下圖所示。
索引(Slot) | 名字(Name) |
---|---|
0 | this |
1 | num |
2 | res |
- 操作數棧: 保存方法執行過程中的臨時結果
- 返回地址: 保存調用該方法的 pc 寄存器的值(即 JVM 指令地址),用於方法結束時,返回調用處,讓調用者方法繼續執行下去
- 動態鏈接: 指向運行時常量池中該棧幀所屬方法的引用,即從常量池中找到目標方法的符號引用,然後轉換為直接引用
附加信息:比如程序 debug 時添加的一些附件信息(不重要,不需要關心,可忽略)
這裏只需要知道它們的作用即可,它們的數據結構、字節碼的含義、執行過程等等,後續的文章我將會針對每個知識點去做詳細的分析。
方法調用過程
先寫一段方法調用的代碼,首先會調用 main()
方法之後調用 fun1()
然後調用 fun2()
,如下圖所示。
現在我們來演示一下 Java 虛擬機執行這些 JVM 指令的過程,首先會調用 main () 方法。
main () 方法
main()
方法執行流程動畫效果如下所示。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ApkZcRTw-1654832156342)(https://img.hi-dhl.com/16541790180176.gif)]
- 執行指令
0: aload_0
,從局部變量錶中,讀取索引為 0 的值,壓入操作數棧中,因為是實例方法,所以索引為 0 的值是 this 的引用
- 執行指令
1: iconst_5
,將常量 5 壓入操作數棧中
- 執行指令
2: invokevirtual #7
,常量 5 和 this 從操作數棧中出棧,然後調用this.fun1(5)
首先從常量池中找到方法 fun1()
的符號引用,然後通過動態鏈接將符號引用轉換成直接引用,之後調用 this.fun1(5)
,將方法 fun1()
作為棧幀壓入虛擬機棧中,跳轉到 fun1()
,繼續往下執行。
如何從常量池中找到目標方法的符號引用,然後轉換成直接引用的過程,將會在後面系列文章中詳細分析
在調用 fun1()
之前,fun1()
的局部變量錶和方法返回地址已經確定好了。
進入方法 fun1 (int num)
方法 fun1(int num)
執行流程動畫效果如下所示。
- 執行指令
0: aload_0
,從局部變量錶中,讀取索引為 0 的值,壓入操作數棧中。因為是實例方法,所以索引為 0 的值是 this 的引用
- 執行指令
1: iload_1
,從局部變量錶中,讀取索引為 1 變量 num 的值,並壓入操作數棧
- 執行指令
2: invokevirtual #13
,num 和 this 從操作數棧中出棧,然後調用this.fun2(num)
首先從常量池中找到方法 fun2()
的符號引用,然後通過動態鏈接將符號引用轉換成直接引用,之後調用 this.fun2(num)
,將方法 fun2()
作為棧幀壓入虛擬機棧中,跳轉到 fun2()
,繼續往下執行,調用 fun2()
之前,fun2()
的局部變量錶和方法返回地址已經確定好了。
進入方法 fun2 (int num)
方法 fun2(int num)
執行流程動畫效果如下所示。
- 執行指令
0: iload_1
,從局部變量錶中,讀取索引為 1 變量 num 的值,並壓入操作數棧中
- 執行指令
1: bipush
,將常量 10 壓入操作數棧中
- 執行指令
3: iadd
,num 和常量 10 從操作數棧中出棧,然後進行相加,將結果壓入操作數棧中
- 執行指令
4: istore_2
,從操作數棧中取出結果,並賦值給局部變量錶中索引為 2 的變量 res2
- 執行指令
5: iload_2
,從局部變量錶中,讀取索引為 2 的變量 res2 的值,並壓入操作數棧中
方法退出過程
每個方法即是一個棧幀,每個棧幀會保存方法返回地址,執行 return
系列指令時,會根據當前棧幀保存的返回地址,返回到調用的比特置,繼續往下執行。因此會分為兩種情况。
异常退出
如果出現了异常且捕獲了該异常,則會從异常錶裏查找 PC 寄存器的地址(JVM 指令地址),返回調用處繼續執行。
正常退出時會做以下件事
- 恢複上一個棧幀局部變量錶、操作數棧
- 如果有返回值,將返回值壓入調用者棧幀的操作數棧,是否有返回值根據
return
JVM 指令:ireturn
:返回值是boolean
、byte
、char
、short
和int
類型lreturn
:返回值是Long
類型freturn
:返回值是Float
類型dreturn
:返回值是Double
類型areturn
:返回值是引用類型return
:返回值類型為void
- 設置調用者棧幀的 JVM 指令地址
- 當前棧幀從虛擬機棧中出棧
這篇文章我們只分析正常退出流程,异常退出和正常退出的流程大致都是一樣的。正常退出流程動畫效果如下所示。
- 方法
fun2
結束時,執行最後一條指令ireturn
,當前棧幀從虛擬機棧中出棧,根據當前棧幀保存的方法返回地址,返回到 fun1 ,恢複 fun1 的局部變量錶、操作數棧,將返回結果res2
保存到調用者(fun1)操作數棧中
- 回到方法
fun1(int num)
,執行指令5: istore_2
,變量res2
從操作數中出棧,賦值給局部變量錶中索引為 2 的變量res1
- 執行指令
6: iload_2
,從局部變量錶中,讀取索引為 2 變量res1
的值,並壓入操作數棧中
- 執行方法 fun1 最後一條指令
7: ireturn
,當前棧幀從虛擬機棧中出棧,根據當前棧幀保存的方法返回地址,返回到 main 方法,恢複 main 方法的局部變量錶、操作數棧,將返回結果res2
保存到調用者(main)操作數棧中
- 最後回到方法
main
中,執行最後一條指令5: pop
,操作數棧中的元素出棧
- 執行最後一條指令
6: return
,至此所有的方法調用結束了,方法所占用的內存,也將返回給系統
每次的方法調用,即是棧幀入棧和出棧的過程,同時也需要占用部分內存,用於保存局部變量錶、操作數棧、方法返回地址、動態鏈接、附加信息等等。
當方法執行完,即棧幀出棧,方法調用所占用的內存,也將返回給系統。
全文到這裏就結束了,感謝你的閱讀,如果有幫助,歡迎 在看
、 點贊
、 收藏
、 分享
給身邊的朋友。
真誠推薦你關注我,公眾號:ByteCode ,持續分享硬核原創內容,Kotlin、Jetpack、性能優化、系統源碼、算法及數據結構、動畫、大廠面經。
近期必讀熱門文章
- 揭秘反射真的很耗時嗎,射 10 萬次耗時多久
- 你知道 Iterable 有多慢嗎?試試它提昇性能
- 揭秘 Kotlin 1.6.20 重磅功能 Context Receivers
- Stack Overflow 上最熱門的 10 個 Kotlin 問題
- Android 12 已來,你的 App 崩潰了嗎?
- Google 宣布廢弃 LiveData.observe 方法
- 影響性能的 Kotlin 代碼(一)
- 揭秘 Kotlin 中的 == 和 ===
最後推薦長期更新和維護的項目
個人博客,將所有文章進行分類,歡迎前去查看 https://hi-dhl.com
KtKit 小巧而實用,用 Kotlin 語言編寫的工具庫,歡迎前去查看 KtKit
計劃建立一個最全、最新的 AndroidX Jetpack 相關組件的實戰項目以及相關組件原理分析文章,正在逐漸增加 Jetpack 新成員,倉庫持續更新,歡迎前去查看 AndroidX-Jetpack-Practice
LeetCode / 劍指 offer / 國內外大廠面試題 / 多線程題解,語言 Java 和 kotlin,包含多種解法、解題思路、時間複雜度、空間複雜度分析
边栏推荐
- Online chain offline integrated chain store e-commerce solution
- OpenGL - Lighting
- LeetCode 496. Next larger element I
- Evolution of Baidu intelligent applet patrol scheduling scheme
- Android 隐私沙盒开发者预览版 3: 隐私安全和个性化体验全都要
- 正式上架!TDengine 插件入驻 Grafana 官网
- Solve the problem of no all pattern found during Navicat activation and registration
- 揭秘百度智能测试在测试自动执行领域实践
- LeetCode 556. Next bigger element III
- [team PK competition] the task of this week has been opened | question answering challenge to consolidate the knowledge of commodity details
猜你喜欢
Evolution of Baidu intelligent applet patrol scheduling scheme
干货整理!ERP在制造业的发展趋势如何,看这一篇就够了
项目实战 | Excel导出功能
从“化学家”到开发者,从甲骨文到 TDengine,我人生的两次重要抉择
植物大战僵尸Scratch
分布式数据库下子查询和 Join 等复杂 SQL 如何实现?
Officially launched! Tdengine plug-in enters the official website of grafana
LeetCode 503. Next bigger Element II
观测云与 TDengine 达成深度合作,优化企业上云体验
Principle and performance analysis of lepton lossless compression
随机推荐
[ManageEngine] how to make good use of the report function of OpManager
Why does everyone want to do e-commerce? How much do you know about the advantages of online shopping malls?
测试老鸟浅谈unittest和pytest的区别
从“化学家”到开发者,从甲骨文到 TDengine,我人生的两次重要抉择
A detailed explanation of the general process and the latest research trends of map comparative learning (gnn+cl)
【sourceTree配置SSH及使用】
Kotlin introductory notes (V) classes and objects, inheritance, constructors
Unity skframework framework (XXIII), minimap small map tool
Alibaba's ten-year test brings you into the world of APP testing
Kotlin introductory notes (VI) interface and function visibility modifiers
Figure neural network + comparative learning, where to go next?
C form click event did not respond
How to improve the operation efficiency of intra city distribution
Principle and performance analysis of lepton lossless compression
[Yugong series] go teaching course 003-ide installation and basic use in July 2022
How do enterprises choose the appropriate three-level distribution system?
Community group buying has triggered heated discussion. How does this model work?
分布式数据库下子查询和 Join 等复杂 SQL 如何实现?
NIPS2021 | 超越GraphCL,GNN+对比学习的节点分类新SOTA
Vs code problem: the length of long lines can be configured through "editor.maxtokenizationlinelength"