// Abstraction to keep monitors small enough to fit in a lock word (32bits). On 32bit systems the // monitor id loses the alignment bits of the Monitor*. class MonitorPool { public: static MonitorPool* Create() { #ifndef __LP64__ return nullptr; #else returnnew MonitorPool(); #endif
}
private: #ifdef __LP64__ // When we create a monitor pool, threads have not been initialized, yet, so ignore thread-safety // analysis.
MonitorPool() NO_THREAD_SAFETY_ANALYSIS;
// Release all chunks and metadata. This is done on shutdown, where threads have been destroyed, // so ignore thead-safety analysis. void FreeInternal() NO_THREAD_SAFETY_ANALYSIS;
// Note: This is safe as we do not ever move chunks. All needed entries in the monitor_chunks_ // data structure are read-only once we get here. Updates happen-before this call because // the lock word was stored with release semantics and we read it with acquire semantics to // retrieve the id.
Monitor* LookupMonitor(MonitorId mon_id) {
size_t offset = MonitorIdToOffset(mon_id);
size_t index = offset / kChunkSize;
size_t top_index = index / kMaxListSize;
size_t list_index = index % kMaxListSize;
size_t offset_in_chunk = offset % kChunkSize;
uintptr_t base = monitor_chunks_[top_index][list_index]; returnreinterpret_cast<Monitor*>(base + offset_in_chunk);
}
// TODO: There are assumptions in the code that monitor addresses are 8B aligned (>>3). static constexpr size_t kMonitorAlignment = 8; // Size of a monitor, rounded up to a multiple of alignment. static constexpr size_t kAlignedMonitorSize = (sizeof(Monitor) + kMonitorAlignment - 1) &
-kMonitorAlignment; // Size of the chunks holding the actual monitors. The bottom bits of the monitor id are the // index into such a chunk. We can collapse this to the actually used storage // in a chunk, i.e., kChunkCapacity * kAlignedMonitorSize, but this would mean proper divisions. static constexpr size_t kChunkSize = 4096;
static_assert(IsPowerOfTwo(kChunkSize), "kChunkSize must be power of 2"); static constexpr size_t kChunkCapacity = kChunkSize / kAlignedMonitorSize; // The number of chunks of storage that can be referenced by the initial chunk list. // The total number of usable monitor chunks is typically 255 times this number, so it // should be large enough that we don't run out. We run out of address bits if it's > 512. // Currently we set it a bit smaller, to save half a page per process. We make it tiny in // debug builds to catch growth errors. The only value we really expect to tune. static constexpr size_t kInitialChunkStorage = kIsDebugBuild ? 8U : 256U;
static_assert(IsPowerOfTwo(kInitialChunkStorage), "kInitialChunkStorage must be power of 2"); // The number of lists, each containing pointers to storage chunks. static constexpr size_t kMaxChunkLists = 8; // Dictated by 3 bit index. Don't increase above 8.
static_assert(IsPowerOfTwo(kMaxChunkLists), "kMaxChunkLists must be power of 2"); static constexpr size_t kMaxListSize = kInitialChunkStorage << (kMaxChunkLists - 1); // We lose 3 bits in monitor id due to 3 bit monitor_chunks_ index, and gain it back from // the 3 bit alignment constraint on monitors:
static_assert(kMaxListSize * kChunkSize < (1 << LockWord::kMonitorIdSize), "Monitor id bits don't fit");
static_assert(IsPowerOfTwo(kMaxListSize), "kMaxListSize must be power of 2");
// Array of pointers to lists (again arrays) of pointers to chunks containing monitors. // Zeroth entry points to a list (array) of kInitialChunkStorage pointers to chunks. // Each subsequent list as twice as large as the preceding one. // Monitor Ids are effectively interpreted as follows: // Top 3 bits (of 28): index into monitor_chunks_. // Next 16 bits: index into the chunk list, i.e. monitor_chunks_[i]. // Last 9 bits: offset within chunk, expressed as multiple of kMonitorAlignment. // If we set kInitialChunkStorage to 512, this would allow us to use roughly 128K chunks of // monitors, which is 0.5GB of monitors. With this maximum setting, the largest chunk list // contains 64K entries, and we make full use of the available index space. With a // kInitialChunkStorage value of 256, this is proportionately reduced to 0.25GB of monitors. // Updates to monitor_chunks_ are guarded by allocated_monitor_ids_lock_ . // No field in this entire data structure is ever updated once a monitor id whose lookup // requires it has been made visible to another thread. Thus readers never race with // updates, in spite of the fact that they acquire no locks.
uintptr_t* monitor_chunks_[kMaxChunkLists]; // uintptr_t is really a Monitor* . // Highest currently used index in monitor_chunks_ . Used for newly allocated chunks.
size_t current_chunk_list_index_ GUARDED_BY(Locks::allocated_monitor_ids_lock_); // Number of chunk pointers stored in monitor_chunks_[current_chunk_list_index_] so far.
size_t num_chunks_ GUARDED_BY(Locks::allocated_monitor_ids_lock_); // After the initial allocation, this is always equal to // ChunkListCapacity(current_chunk_list_index_).
size_t current_chunk_list_capacity_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
using Allocator = TrackingAllocator<uint8_t, kAllocatorTagMonitorPool>;
Allocator allocator_;
// Start of free list of monitors. // Note: these point to the right memory regions, but do *not* denote initialized objects.
Monitor* first_free_ GUARDED_BY(Locks::allocated_monitor_ids_lock_); #endif
};
} // namespace art
#endif// ART_RUNTIME_MONITOR_POOL_H_
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.