看ART代码过程中,看到LogContentionEvent函数,记起logcat events中有大量的dvm_lock_sample信息。
dvm_lock_sample: [com.banyac.midrive.map,1,main,98,ReportUtil.java,119,-,189,19]
进程名,主线程?线程名,锁等待时间,下个持有者文件名,行号,上个持有者文件名,行号,等待百分比
- 打印此LOG时,线程即将持有锁。
- 上一个持有者文件名为“-”时,表示与下个持有者在同一个文件中
- 发生锁等待时这个LOG有概率打印,等待百分比越大,概率越大。具体请看代码。
art/runtime/monitor.cc
void Monitor::Lock(Thread* self) {
MutexLock mu(self, monitor_lock_);
while (true) {
if (owner_ == nullptr) { // Unowned.
owner_ = self;
CHECK_EQ(lock_count_, 0);
// When debugging, save the current monitor holder for future
// acquisition failures to use in sampled logging.
if (lock_profiling_threshold_ != 0) {
locking_method_ = self->GetCurrentMethod(&locking_dex_pc_);
}
return;
} else if (owner_ == self) { // Recursive.
lock_count_++;
return;
}
// Contended.
const bool log_contention = (lock_profiling_threshold_ != 0);
uint64_t wait_start_ms = log_contention ? MilliTime() : 0;
mirror::ArtMethod* owners_method = locking_method_;
uint32_t owners_dex_pc = locking_dex_pc_;
// Do this before releasing the lock so that we don't get deflated.
size_t num_waiters = num_waiters_;
++num_waiters_;
monitor_lock_.Unlock(self); // Let go of locks in order.
self->SetMonitorEnterObject(GetObject());
{
ScopedThreadStateChange tsc(self, kBlocked); // Change to blocked and give up mutator_lock_.
MutexLock mu2(self, monitor_lock_); // Reacquire monitor_lock_ without mutator_lock_ for Wait.
if (owner_ != NULL) { // Did the owner_ give the lock up?
monitor_contenders_.Wait(self); // Still contended so wait.
// Woken from contention.
if (log_contention) {
uint64_t wait_ms = MilliTime() - wait_start_ms;
uint32_t sample_percent;
if (wait_ms >= lock_profiling_threshold_) {
sample_percent = 100;
} else {
sample_percent = 100 * wait_ms / lock_profiling_threshold_;
}
if (sample_percent != 0 && (static_cast<uint32_t>(rand() % 100) < sample_percent)) {
const char* owners_filename;
uint32_t owners_line_number;
TranslateLocation(owners_method, owners_dex_pc, &owners_filename, &owners_line_number);
if (wait_ms > kLongWaitMs && owners_method != nullptr) {
LOG(WARNING) << "Long monitor contention event with owner method="
<< PrettyMethod(owners_method) << " from " << owners_filename << ":"
<< owners_line_number << " waiters=" << num_waiters << " for "
<< PrettyDuration(MsToNs(wait_ms));
}
LogContentionEvent(self, wait_ms, sample_percent, owners_filename, owners_line_number);
}
}
}
}
self->SetMonitorEnterObject(nullptr);
monitor_lock_.Lock(self); // Reacquire locks in order.
--num_waiters_;
}
}