Java 工具(jmap,jstack)在linux上的源碼分析(四)safe point__資料結構

來源:互聯網
上載者:User

safe point 顧明思意,就是安全點,當需要jvm做一些操作的時候,需要把當前正在啟動並執行線程進入一個安全點的狀態(也可以說停止狀態),這樣才能做一些安全的操作,比如線程的dump,堆棧的資訊。

在jvm裡面通常vm_thread(我們一直在談論的做一些屬於vm 份內事情的線程) 和cms_thread(記憶體回收的線程)做的操作,是需要將其他的線程通過調用SafepointSynchronize::begin 和 SafepointSynchronize:end來實現讓其他的線程進入或者退出safe point 的狀態。 通常safepoint 的有三種狀態

_not_synchronized 說明沒有任何打斷現在所有線程啟動並執行操作,也就是vm thread, cms thread 沒有接到操作的指令
_synchronizing vm thread,cms thread 接到操作指令,正在等待所有線程進入safe point
_synchronized 所有線程進入safe point, vm thread, cms thread 可以開始指令操作

  Java線程的狀態

通常在java 進程中的Java 的線程有幾個不同的狀態,如何讓這些線程進入safepoint 的狀態中,jvm是採用不同的方式 a. 正在解釋執行

由於java是解釋性語言,而線程在解釋java 位元組碼的時候,需要dispatch table,記錄方法地址進行跳轉的,那麼這樣讓線程進入停止狀態就比較容易了,只要替換掉dispatch table 就可以了,讓線程知道當前進入softpoint 狀態。

java裡會設定3個DispatchTable,  _active_table,  _normal_table, _safept_table

_active_table 正在解釋啟動並執行線程使用的dispatch table

_normal_table 就是正常啟動並執行初始化的dispatch table

_safept_table safe point需要的dispatch table

 

解釋啟動並執行線程一直都在使用_active_table,關鍵處就是在進入saftpoint 的時候,用_safept_table替換_active_table, 在退出saftpoint 的時候,使用_normal_table來替換_active_table

具體實現可以查看源碼

void TemplateInterpreter::notice_safepoints() {  if (!_notice_safepoints) {    // switch to safepoint dispatch table    _notice_safepoints = true;    copy_table((address*)&_safept_table, (address*)&_active_table, sizeof(_active_table) / sizeof(address));  }}// switch from the dispatch table which notices safepoints back to the// normal dispatch table.  So that we can notice single stepping points,// keep the safepoint dispatch table if we are single stepping in JVMTI.// Note that the should_post_single_step test is exactly as fast as the// JvmtiExport::_enabled test and covers both cases.void TemplateInterpreter::ignore_safepoints() {  if (_notice_safepoints) {    if (!JvmtiExport::should_post_single_step()) {      // switch to normal dispatch table      _notice_safepoints = false;      copy_table((address*)&_normal_table, (address*)&_active_table, sizeof(_active_table) / sizeof(address));    }  }}

b. 運行在native code

如果線程運行在native code的時候,vm thread 是不需要等待線程執行完的,只需要在從native code 返回的時候去判斷一下 _state 的狀態就可以了。

在方法體裡就是前面部落格也出現過的 SafepointSynchronize::do_call_back()

  inline static bool do_call_back() {    return (_state != _not_synchronized);  }

判斷了_state 不是_not_synchronized狀態

為了能讓線程從native code 回到java 的時候為了能讀到/設定正確線程的狀態,通常的解決方案使用memory barrier,java 使用OrderAccess::fence(); 在彙編裡使用__asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory"); 保證從記憶體裡讀到正確的值,但是這種方法嚴重影響系統的效能,於是java使用了每個線程都有獨立的記憶體頁來設定狀態。通過使用使用參數-XX:+UseMembar  參數使用memory barrier,預設是不開啟的,也就是使用獨立的記憶體頁來設定狀態。


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.