diff options
| -rw-r--r-- | runtime/gc/heap.cc | 132 | ||||
| -rw-r--r-- | runtime/gc/heap.h | 27 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_VMRuntime.cc | 5 |
3 files changed, 31 insertions, 133 deletions
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 5e62729c2e..1e3689bbda 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -107,9 +107,8 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max activity_thread_(NULL), application_thread_(NULL), last_process_state_id_(NULL), - // Initially care about pauses in case we never get notified of process states, or if the JNI - // code becomes broken. - care_about_pause_times_(true), + // Initially assume we perceive jank in case the process state is never updated. + process_state_(kProcessStateJankPerceptible), concurrent_start_bytes_(concurrent_gc_ ? initial_size - kMinConcurrentRemainingBytes : std::numeric_limits<size_t>::max()), total_bytes_freed_ever_(0), @@ -325,6 +324,10 @@ void Heap::DecrementDisableGC(Thread* self) { --gc_disable_count_; } +void Heap::UpdateProcessState(ProcessState process_state) { + process_state_ = process_state; +} + void Heap::CreateThreadPool() { const size_t num_threads = std::max(parallel_gc_threads_, conc_gc_threads_); if (num_threads != 0) { @@ -373,124 +376,6 @@ void Heap::DeleteThreadPool() { thread_pool_.reset(nullptr); } -static bool ReadStaticInt(JNIEnvExt* env, jclass clz, const char* name, int* out_value) { - DCHECK(out_value != NULL); - jfieldID field = env->GetStaticFieldID(clz, name, "I"); - if (field == NULL) { - env->ExceptionClear(); - return false; - } - *out_value = env->GetStaticIntField(clz, field); - return true; -} - -void Heap::ListenForProcessStateChange() { - VLOG(heap) << "Heap notified of process state change"; - - Thread* self = Thread::Current(); - JNIEnvExt* env = self->GetJniEnv(); - - if (!have_zygote_space_) { - return; - } - - if (activity_thread_class_ == NULL) { - jclass clz = env->FindClass("android/app/ActivityThread"); - if (clz == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not find activity thread class in process state change"; - return; - } - activity_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz)); - } - - if (activity_thread_class_ != NULL && activity_thread_ == NULL) { - jmethodID current_activity_method = env->GetStaticMethodID(activity_thread_class_, - "currentActivityThread", - "()Landroid/app/ActivityThread;"); - if (current_activity_method == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not get method for currentActivityThread"; - return; - } - - jobject obj = env->CallStaticObjectMethod(activity_thread_class_, current_activity_method); - if (obj == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not get current activity"; - return; - } - activity_thread_ = env->NewGlobalRef(obj); - } - - if (process_state_cares_about_pause_time_.empty()) { - // Just attempt to do this the first time. - jclass clz = env->FindClass("android/app/ActivityManager"); - if (clz == NULL) { - LOG(WARNING) << "Activity manager class is null"; - return; - } - ScopedLocalRef<jclass> activity_manager(env, clz); - std::vector<const char*> care_about_pauses; - care_about_pauses.push_back("PROCESS_STATE_TOP"); - care_about_pauses.push_back("PROCESS_STATE_IMPORTANT_BACKGROUND"); - // Attempt to read the constants and classify them as whether or not we care about pause times. - for (size_t i = 0; i < care_about_pauses.size(); ++i) { - int process_state = 0; - if (ReadStaticInt(env, activity_manager.get(), care_about_pauses[i], &process_state)) { - process_state_cares_about_pause_time_.insert(process_state); - VLOG(heap) << "Adding process state " << process_state - << " to set of states which care about pause time"; - } - } - } - - if (application_thread_class_ == NULL) { - jclass clz = env->FindClass("android/app/ActivityThread$ApplicationThread"); - if (clz == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not get application thread class"; - return; - } - application_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz)); - last_process_state_id_ = env->GetFieldID(application_thread_class_, "mLastProcessState", "I"); - if (last_process_state_id_ == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not get last process state member"; - return; - } - } - - if (application_thread_class_ != NULL && application_thread_ == NULL) { - jmethodID get_application_thread = - env->GetMethodID(activity_thread_class_, "getApplicationThread", - "()Landroid/app/ActivityThread$ApplicationThread;"); - if (get_application_thread == NULL) { - LOG(WARNING) << "Could not get method ID for get application thread"; - return; - } - - jobject obj = env->CallObjectMethod(activity_thread_, get_application_thread); - if (obj == NULL) { - LOG(WARNING) << "Could not get application thread"; - return; - } - - application_thread_ = env->NewGlobalRef(obj); - } - - if (application_thread_ != NULL && last_process_state_id_ != NULL) { - int process_state = env->GetIntField(application_thread_, last_process_state_id_); - env->ExceptionClear(); - - care_about_pause_times_ = process_state_cares_about_pause_time_.find(process_state) != - process_state_cares_about_pause_time_.end(); - - VLOG(heap) << "New process state " << process_state - << " care about pauses " << care_about_pause_times_; - } -} - void Heap::AddSpace(space::Space* space) { DCHECK(space != NULL); WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); @@ -1426,7 +1311,7 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus // Grow the heap so that we know when to perform the next GC. GrowForUtilization(gc_type, collector->GetDurationNs()); - if (care_about_pause_times_) { + if (CareAboutPauseTimes()) { const size_t duration = collector->GetDurationNs(); std::vector<uint64_t> pauses = collector->GetPauseTimes(); // GC for alloc pauses the allocating thread, so consider it as a pause. @@ -2143,10 +2028,9 @@ void Heap::RequestHeapTrim() { } last_trim_time_ms_ = ms_time; - ListenForProcessStateChange(); // Trim only if we do not currently care about pause times. - if (!care_about_pause_times_) { + if (!CareAboutPauseTimes()) { JNIEnv* env = self->GetJniEnv(); DCHECK(WellKnownClasses::java_lang_Daemons != NULL); DCHECK(WellKnownClasses::java_lang_Daemons_requestHeapTrim != NULL); diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 8c5746de36..046fbac319 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -119,6 +119,18 @@ static constexpr HeapVerificationMode kDesiredHeapVerification = kNoHeapVerifica // If true, use rosalloc/RosAllocSpace instead of dlmalloc/DlMallocSpace static constexpr bool kUseRosAlloc = true; +// The process state passed in from the activity manager, used to determine when to do trimming +// and compaction. +enum ProcessState { + kProcessStateJankPerceptible = 0, + kProcessStateJankImperceptible = 1, +}; + +// If true, measure the total allocation time. +static constexpr bool kMeasureAllocationTime = false; +// Primitive arrays larger than this size are put in the large object space. +static constexpr size_t kLargeObjectThreshold = 3 * kPageSize; + class Heap { public: // If true, measure the total allocation time. @@ -287,6 +299,9 @@ class Heap { // waited for. collector::GcType WaitForGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_); + // Update the heap's process state to a new value, may cause compaction to occur. + void UpdateProcessState(ProcessState process_state); + const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const { return continuous_spaces_; } @@ -451,10 +466,7 @@ class Heap { // Mark the specified allocation stack as live. void MarkAllocStackAsLive(accounting::ObjectStack* stack) - EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); - - // Gets called when we get notified by ActivityThread that the process state has changed. - void ListenForProcessStateChange(); + EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); // DEPRECATED: Should remove in "near" future when support for multiple image spaces is added. // Assumes there is only one image space. @@ -475,7 +487,7 @@ class Heap { // Returns true if we currently care about pause times. bool CareAboutPauseTimes() const { - return care_about_pause_times_; + return process_state_ == kProcessStateJankPerceptible; } // Thread pool. @@ -713,11 +725,8 @@ class Heap { jobject application_thread_; jfieldID last_process_state_id_; - // Process states which care about pause times. - std::set<int> process_state_cares_about_pause_time_; - // Whether or not we currently care about pause times. - bool care_about_pause_times_; + ProcessState process_state_; // When num_bytes_allocated_ exceeds this amount then a concurrent GC should be requested so that // it completes ahead of an allocation failing. diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index fd3d91ef99..726a8f1769 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -166,6 +166,10 @@ static void VMRuntime_registerNativeFree(JNIEnv* env, jobject, jint bytes) { Runtime::Current()->GetHeap()->RegisterNativeFree(env, bytes); } +static void VMRuntime_updateProcessState(JNIEnv* env, jobject, jint process_state) { + Runtime::Current()->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state)); +} + static void VMRuntime_trimHeap(JNIEnv*, jobject) { Runtime::Current()->GetHeap()->Trim(); } @@ -496,6 +500,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"), NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"), NATIVE_METHOD(VMRuntime, registerNativeFree, "(I)V"), + NATIVE_METHOD(VMRuntime, updateProcessState, "(I)V"), NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"), NATIVE_METHOD(VMRuntime, trimHeap, "()V"), NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"), |