summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2015-06-05 13:21:05 -0700
committerMathieu Chartier <mathieuc@google.com>2015-06-05 16:16:38 -0700
commit3b532d744034b43ed329a3198f15846d80fec3f0 (patch)
tree05195156ad2d516396d88c8356d4fc9916c089f1 /runtime
parent7fabaa6ba1927d21a317c03499b705cbde4f6a47 (diff)
downloadart-3b532d744034b43ed329a3198f15846d80fec3f0.zip
art-3b532d744034b43ed329a3198f15846d80fec3f0.tar.gz
art-3b532d744034b43ed329a3198f15846d80fec3f0.tar.bz2
Use runFinalizationWithTimeout for native allocations
Prevents deadlocks by not waiting longer than 250ms for finalizers to complete. Bug: 21544853 Change-Id: I57b2f7ae8b74185922eb3c15ba0ab71a4d2348aa
Diffstat (limited to 'runtime')
-rw-r--r--runtime/base/time_utils.h4
-rw-r--r--runtime/gc/heap.cc23
-rw-r--r--runtime/gc/heap.h4
-rw-r--r--runtime/well_known_classes.cc5
-rw-r--r--runtime/well_known_classes.h2
5 files changed, 21 insertions, 17 deletions
diff --git a/runtime/base/time_utils.h b/runtime/base/time_utils.h
index f58c22a..55d2764 100644
--- a/runtime/base/time_utils.h
+++ b/runtime/base/time_utils.h
@@ -68,8 +68,8 @@ static constexpr inline uint64_t NsToMs(uint64_t ns) {
}
// Converts the given number of milliseconds to nanoseconds
-static constexpr inline uint64_t MsToNs(uint64_t ns) {
- return ns * 1000 * 1000;
+static constexpr inline uint64_t MsToNs(uint64_t ms) {
+ return ms * 1000 * 1000;
}
#if defined(__APPLE__)
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d344d81..aeab7d8 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -110,6 +110,9 @@ static constexpr size_t kVerifyObjectAllocationStackSize = 16 * KB /
sizeof(mirror::HeapReference<mirror::Object>);
static constexpr size_t kDefaultAllocationStackSize = 8 * MB /
sizeof(mirror::HeapReference<mirror::Object>);
+// System.runFinalization can deadlock with native allocations, to deal with this, we have a
+// timeout on how long we wait for finalizers to run. b/21544853
+static constexpr uint64_t kNativeAllocationFinalizeTimeout = MsToNs(250u);
Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
double target_utilization, double foreground_heap_growth_multiplier,
@@ -3538,22 +3541,16 @@ bool Heap::IsGCRequestPending() const {
return concurrent_gc_pending_.LoadRelaxed();
}
-void Heap::RunFinalization(JNIEnv* env) {
- // Can't do this in WellKnownClasses::Init since System is not properly set up at that point.
- if (WellKnownClasses::java_lang_System_runFinalization == nullptr) {
- CHECK(WellKnownClasses::java_lang_System != nullptr);
- WellKnownClasses::java_lang_System_runFinalization =
- CacheMethod(env, WellKnownClasses::java_lang_System, true, "runFinalization", "()V");
- CHECK(WellKnownClasses::java_lang_System_runFinalization != nullptr);
- }
- env->CallStaticVoidMethod(WellKnownClasses::java_lang_System,
- WellKnownClasses::java_lang_System_runFinalization);
+void Heap::RunFinalization(JNIEnv* env, uint64_t timeout) {
+ env->CallStaticVoidMethod(WellKnownClasses::dalvik_system_VMRuntime,
+ WellKnownClasses::dalvik_system_VMRuntime_runFinalization,
+ static_cast<jlong>(timeout));
}
void Heap::RegisterNativeAllocation(JNIEnv* env, size_t bytes) {
Thread* self = ThreadForEnv(env);
if (native_need_to_run_finalization_) {
- RunFinalization(env);
+ RunFinalization(env, kNativeAllocationFinalizeTimeout);
UpdateMaxNativeFootprint();
native_need_to_run_finalization_ = false;
}
@@ -3569,7 +3566,7 @@ void Heap::RegisterNativeAllocation(JNIEnv* env, size_t bytes) {
if (new_native_bytes_allocated > growth_limit_) {
if (WaitForGcToComplete(kGcCauseForNativeAlloc, self) != collector::kGcTypeNone) {
// Just finished a GC, attempt to run finalizers.
- RunFinalization(env);
+ RunFinalization(env, kNativeAllocationFinalizeTimeout);
CHECK(!env->ExceptionCheck());
// Native bytes allocated may be updated by finalization, refresh it.
new_native_bytes_allocated = native_bytes_allocated_.LoadRelaxed();
@@ -3577,7 +3574,7 @@ void Heap::RegisterNativeAllocation(JNIEnv* env, size_t bytes) {
// If we still are over the watermark, attempt a GC for alloc and run finalizers.
if (new_native_bytes_allocated > growth_limit_) {
CollectGarbageInternal(gc_type, kGcCauseForNativeAlloc, false);
- RunFinalization(env);
+ RunFinalization(env, kNativeAllocationFinalizeTimeout);
native_need_to_run_finalization_ = false;
CHECK(!env->ExceptionCheck());
}
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index c72414a..81a9741 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -776,8 +776,8 @@ class Heap {
bool IsValidContinuousSpaceObjectAddress(const mirror::Object* obj) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Run the finalizers.
- void RunFinalization(JNIEnv* env);
+ // Run the finalizers. If timeout is non zero, then we use the VMRuntime version.
+ void RunFinalization(JNIEnv* env, uint64_t timeout);
// Blocks the caller until the garbage collector becomes idle and returns the type of GC we
// waited for.
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 3dbfe1b..e7857a0 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -34,6 +34,7 @@ jclass WellKnownClasses::dalvik_system_DexFile;
jclass WellKnownClasses::dalvik_system_DexPathList;
jclass WellKnownClasses::dalvik_system_DexPathList__Element;
jclass WellKnownClasses::dalvik_system_PathClassLoader;
+jclass WellKnownClasses::dalvik_system_VMRuntime;
jclass WellKnownClasses::java_lang_BootClassLoader;
jclass WellKnownClasses::java_lang_ClassLoader;
jclass WellKnownClasses::java_lang_ClassNotFoundException;
@@ -63,6 +64,7 @@ jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk;
jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer;
jmethodID WellKnownClasses::com_android_dex_Dex_create;
+jmethodID WellKnownClasses::dalvik_system_VMRuntime_runFinalization;
jmethodID WellKnownClasses::java_lang_Boolean_valueOf;
jmethodID WellKnownClasses::java_lang_Byte_valueOf;
jmethodID WellKnownClasses::java_lang_Character_valueOf;
@@ -209,6 +211,8 @@ void WellKnownClasses::Init(JNIEnv* env) {
dalvik_system_DexPathList = CacheClass(env, "dalvik/system/DexPathList");
dalvik_system_DexPathList__Element = CacheClass(env, "dalvik/system/DexPathList$Element");
dalvik_system_PathClassLoader = CacheClass(env, "dalvik/system/PathClassLoader");
+ dalvik_system_VMRuntime = CacheClass(env, "dalvik/system/VMRuntime");
+
java_lang_BootClassLoader = CacheClass(env, "java/lang/BootClassLoader");
java_lang_ClassLoader = CacheClass(env, "java/lang/ClassLoader");
java_lang_ClassNotFoundException = CacheClass(env, "java/lang/ClassNotFoundException");
@@ -238,6 +242,7 @@ void WellKnownClasses::Init(JNIEnv* env) {
org_apache_harmony_dalvik_ddmc_Chunk = CacheClass(env, "org/apache/harmony/dalvik/ddmc/Chunk");
org_apache_harmony_dalvik_ddmc_DdmServer = CacheClass(env, "org/apache/harmony/dalvik/ddmc/DdmServer");
+ dalvik_system_VMRuntime_runFinalization = CacheMethod(env, dalvik_system_VMRuntime, true, "runFinalization", "(J)V");
com_android_dex_Dex_create = CacheMethod(env, com_android_dex_Dex, true, "create", "(Ljava/nio/ByteBuffer;)Lcom/android/dex/Dex;");
java_lang_ClassNotFoundException_init = CacheMethod(env, java_lang_ClassNotFoundException, false, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
java_lang_ClassLoader_loadClass = CacheMethod(env, java_lang_ClassLoader, false, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index d25d1c3..66b9abe 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -45,6 +45,7 @@ struct WellKnownClasses {
static jclass dalvik_system_DexPathList;
static jclass dalvik_system_DexPathList__Element;
static jclass dalvik_system_PathClassLoader;
+ static jclass dalvik_system_VMRuntime;
static jclass java_lang_BootClassLoader;
static jclass java_lang_ClassLoader;
static jclass java_lang_ClassNotFoundException;
@@ -74,6 +75,7 @@ struct WellKnownClasses {
static jclass org_apache_harmony_dalvik_ddmc_DdmServer;
static jmethodID com_android_dex_Dex_create;
+ static jmethodID dalvik_system_VMRuntime_runFinalization;
static jmethodID java_lang_Boolean_valueOf;
static jmethodID java_lang_Byte_valueOf;
static jmethodID java_lang_Character_valueOf;