Java知識學習——虛擬機棧與本地方法棧

虛擬機棧,顧名思義,與我們熟知的數據結構——棧一樣。虛擬機棧就是線程運行時所需要的空間,每一個棧內又是以多個棧幀所構成,什麼是棧幀?一個棧幀對應了一次方法的調用,即每個方法運行時所需要的內存就是棧幀,方法運行時方法參數、局部變量、返回地址這些都需要佔用空間的。棧和棧幀是怎麼聯繫的呢?例如一段代碼在執行的時候調用第一個方法,就會給第一個方法分配一個空間並壓入棧中,當第一個方法執行完成之後,就會把這個方法對應的棧幀從棧中移除,即釋放對應的內存,這就是棧和棧幀之間的關係,一個棧內可以有多個棧幀。

每個線程只能有一個活動棧幀,對應着當前正在執行的那個方法。

垃圾回收是否會管理棧內存?答案是不需要的,因爲棧內存無非就是一次次的方法調用所產生的棧幀內存,而棧幀內存在每次方法調用結束之後,都會彈出棧,就是會自動的被回收掉,所以也就是不需要垃圾回收來管理棧內存。垃圾回收主要是回收堆內存的無用對象。

棧內存的分配越大越好嗎?棧內存可以通過運行時虛擬機參數來指定(-Xss+大小)。棧內存劃分越大反而會使線程數越少 ,物理內存的大小是固定的,例如一個線程使用的是棧內存,一個線程假設使用了1M內存,物理內存假設有500M,理論上我可以有500個線程同時運行,但是如果設置每個線程使用2M的內存,理論上只有250個線程同時運行。所以棧內存並不是劃分的越大越好,劃分的大隻是利於更多的方法遞歸調用而不會增強運行的效率,反而會影響線程的運行數量。

方法內的局部變量是否是線程安全的?看一個變量是否是線程安全的,其實只需要看它到底是多個線程對這個變量是共享的還是私有的?如果方法內局部變量沒有逃離方法的作用範圍,它就是線程安全的,反之就可能存在線程安全。如果這個局部變量引用了對象並逃離了方法的作用範圍,就需要考慮線程的安全問題。

虛擬機棧中會存在內存溢出,出現內存溢出是有兩個方面所引起的:棧幀過多導致(遞歸調用無結束的條件)和棧幀過大導致。

線程運行的診斷——CPU佔用過高。用TOP命令定位哪個進程對CPU過高,用PS命令進一步確認哪個線程引起的CPU過高,最後用jstack +進程ID(Jstack 可以根據線程ID找到有問題的線程,進一步定位到有問題的代碼行數,在Jstack裏面都是16進制,所以在找的時候需要換算一下)。

線程運行的診斷——程序運行很長時間沒有結果。同樣是可以採用Jstack命令查看具體的線程問題,以及具體有問題的代碼行數。Jstack中也會在最後中顯示死鎖的信息。

 

本地方法棧,本地方法棧實際上就是在Java虛擬機在調用本地方法時需要給本地方法提供一個內存空間,就是指不是由Java代碼編寫的方法,Java代碼是有一定的限制的,有的時候它不能直接與我們的操作系統底層打交道,所以就需要用C或者C++語言編寫的本地方法來與底層操作系統打交道,Java代碼可以間接調用本地方法來調用底層的一些功能,本地方法運行的時候所要用到的內存就是我們的本地方法棧。例如Object類中的clone()、hashCode()。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章