Add parsed options for heap min free, heap max free, target utilization.
Added options in runtime for heap min free, max free, and target utilization.
Change-Id: Iaea988ffbf6cb7f07127640786168de7d341f1e1
diff --git a/src/common_test.h b/src/common_test.h
index 62ff907..560edeb 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -322,8 +322,8 @@
java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName(), GetLibCoreDexFileName());
boot_class_path_.push_back(java_lang_dex_file_);
- std::string min_heap_string(StringPrintf("-Xms%zdm", Heap::kInitialSize / MB));
- std::string max_heap_string(StringPrintf("-Xmx%zdm", Heap::kMaximumSize / MB));
+ std::string min_heap_string(StringPrintf("-Xms%zdm", Heap::kDefaultInitialSize / MB));
+ std::string max_heap_string(StringPrintf("-Xmx%zdm", Heap::kDefaultMaximumSize / MB));
Runtime::Options options;
options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL)));
diff --git a/src/heap.cc b/src/heap.cc
index 6c13563..f91ce84 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -45,6 +45,8 @@
namespace art {
+const double Heap::kDefaultTargetUtilization = 0.5;
+
static bool GenerateImage(const std::string& image_file_name) {
const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
std::vector<std::string> boot_class_path;
@@ -127,7 +129,8 @@
oat_file_map_.reset(NULL);
}
-Heap::Heap(size_t initial_size, size_t growth_limit, size_t capacity,
+Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
+ double target_utilization, size_t capacity,
const std::string& original_image_file_name, bool concurrent_gc)
: alloc_space_(NULL),
card_table_(NULL),
@@ -138,10 +141,10 @@
last_gc_type_(kGcTypeNone),
enforce_heap_growth_rate_(false),
growth_limit_(growth_limit),
- max_allowed_footprint_(kInitialSize),
- concurrent_start_bytes_(std::numeric_limits<size_t>::max()),
+ max_allowed_footprint_(initial_size),
concurrent_start_size_(128 * KB),
concurrent_min_free_(256 * KB),
+ concurrent_start_bytes_(initial_size - concurrent_start_size_),
sticky_gc_count_(0),
total_bytes_freed_(0),
total_objects_freed_(0),
@@ -163,7 +166,9 @@
reference_queueNext_offset_(0),
reference_pendingNext_offset_(0),
finalizer_reference_zombie_offset_(0),
- target_utilization_(0.5),
+ min_free_(min_free),
+ max_free_(max_free),
+ target_utilization_(target_utilization),
total_paused_time_(0),
total_wait_time_(0),
measure_allocation_time_(false),
@@ -730,10 +735,6 @@
return TryToAllocate(self, space, alloc_size, true);
}
-float Heap::GetTargetHeapUtilization() const {
- return target_utilization_;
-}
-
void Heap::SetTargetHeapUtilization(float target) {
DCHECK_GT(target, 0.0f); // asserted in Java code
DCHECK_LT(target, 1.0f);
@@ -1763,7 +1764,8 @@
uint64_t pause_dirty = (dirty_end - dirty_begin) / 1000 * 1000;
uint64_t duration = (NanoTime() - root_begin) / 1000 * 1000;
total_paused_time_ += (pause_roots + pause_dirty) / kTimeAdjust;
- if (pause_roots > MsToNs(5) || pause_dirty > MsToNs(5)) {
+ if (pause_roots > MsToNs(5) || pause_dirty > MsToNs(5) ||
+ (gc_cause == kGcCauseForAlloc && duration > MsToNs(20))) {
const size_t percent_free = GetPercentFree();
const size_t current_heap_size = GetUsedMemorySize();
const size_t total_memory = GetTotalMemory();
@@ -1833,20 +1835,14 @@
max_allowed_footprint_ = max_allowed_footprint;
}
-// kHeapIdealFree is the ideal maximum free size, when we grow the heap for utilization.
-static const size_t kHeapIdealFree = 2 * MB;
-// kHeapMinFree guarantees that you always have at least 512 KB free, when you grow for utilization,
-// regardless of target utilization ratio.
-static const size_t kHeapMinFree = kHeapIdealFree / 4;
-
void Heap::GrowForUtilization() {
// We know what our utilization is at this moment.
// This doesn't actually resize any memory. It just lets the heap grow more when necessary.
size_t target_size = num_bytes_allocated_ / Heap::GetTargetHeapUtilization();
- if (target_size > num_bytes_allocated_ + kHeapIdealFree) {
- target_size = num_bytes_allocated_ + kHeapIdealFree;
- } else if (target_size < num_bytes_allocated_ + kHeapMinFree) {
- target_size = num_bytes_allocated_ + kHeapMinFree;
+ if (target_size > num_bytes_allocated_ + max_free_) {
+ target_size = num_bytes_allocated_ + max_free_;
+ } else if (target_size < num_bytes_allocated_ + min_free_) {
+ target_size = num_bytes_allocated_ + min_free_;
}
// Calculate when to perform the next ConcurrentGC.
diff --git a/src/heap.h b/src/heap.h
index d5f1ba7..6cd19d4 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -82,8 +82,14 @@
class Heap {
public:
- static const size_t kInitialSize = 2 * MB;
- static const size_t kMaximumSize = 32 * MB;
+ static const size_t kDefaultInitialSize = 2 * MB;
+ static const size_t kDefaultMaximumSize = 32 * MB;
+ static const size_t kDefaultMaxFree = 2 * MB;
+ static const size_t kDefaultMinFree = kDefaultMaxFree / 4;
+
+ // Default target utilization.
+ static const double kDefaultTargetUtilization;
+
// Used so that we don't overflow the allocation time atomic integer.
static const size_t kTimeAdjust = 1024;
@@ -93,8 +99,9 @@
// Create a heap with the requested sizes. The possible empty
// image_file_names names specify Spaces to load based on
// ImageWriter output.
- explicit Heap(size_t starting_size, size_t growth_limit, size_t capacity,
- const std::string& image_file_name, bool concurrent_gc);
+ explicit Heap(size_t initial_size, size_t growth_limit, size_t min_free,
+ size_t max_free, double target_utilization, size_t capacity,
+ const std::string& original_image_file_name, bool concurrent_gc);
~Heap();
@@ -155,7 +162,9 @@
// Target ideal heap utilization ratio, implements
// dalvik.system.VMRuntime.getTargetHeapUtilization.
- float GetTargetHeapUtilization() const;
+ double GetTargetHeapUtilization() const {
+ return target_utilization_;
+ }
// Set target ideal heap utilization ratio, implements
// dalvik.system.VMRuntime.setTargetHeapUtilization.
@@ -425,9 +434,9 @@
size_t max_allowed_footprint_;
// Bytes until concurrent GC starts.
- volatile size_t concurrent_start_bytes_;
size_t concurrent_start_size_;
size_t concurrent_min_free_;
+ size_t concurrent_start_bytes_;
// Number of bytes allocated since the last Gc, we use this to help determine when to schedule concurrent GCs.
size_t bytes_since_last_gc_;
@@ -498,8 +507,15 @@
// offset of java.lang.ref.FinalizerReference.zombie
MemberOffset finalizer_reference_zombie_offset_;
+ // Minimum free guarantees that you always have at least min_free_ free bytes after growing for
+ // utilization, regardless of target utilization ratio.
+ size_t min_free_;
+
+ // The ideal maximum free size, when we grow the heap for utilization.
+ size_t max_free_;
+
// Target ideal heap utilization ratio
- float target_utilization_;
+ double target_utilization_;
// Total time which mutators are paused or waiting for GC to complete.
uint64_t total_paused_time_;
diff --git a/src/runtime.cc b/src/runtime.cc
index e3384df..e2e419a 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -347,8 +347,11 @@
// -Xcheck:jni is off by default for regular builds but on by default in debug builds.
parsed->check_jni_ = kIsDebugBuild;
- parsed->heap_initial_size_ = Heap::kInitialSize;
- parsed->heap_maximum_size_ = Heap::kMaximumSize;
+ parsed->heap_initial_size_ = Heap::kDefaultInitialSize;
+ parsed->heap_maximum_size_ = Heap::kDefaultMaximumSize;
+ parsed->heap_min_free_ = Heap::kDefaultMinFree;
+ parsed->heap_max_free_ = Heap::kDefaultMaxFree;
+ parsed->heap_target_utilization_ = Heap::kDefaultTargetUtilization;
parsed->heap_growth_limit_ = 0; // 0 means no growth limit.
parsed->stack_size_ = 0; // 0 means default.
@@ -443,6 +446,42 @@
return NULL;
}
parsed->heap_growth_limit_ = size;
+ } else if (StartsWith(option, "-XX:HeapMinFree=")) {
+ size_t size = ParseMemoryOption(option.substr(strlen("-XX:HeapMinFree=")).c_str(), 1024);
+ if (size == 0) {
+ if (ignore_unrecognized) {
+ continue;
+ }
+ // TODO: usage
+ LOG(FATAL) << "Failed to parse " << option;
+ return NULL;
+ }
+ parsed->heap_min_free_ = size;
+ } else if (StartsWith(option, "-XX:HeapMaxFree=")) {
+ size_t size = ParseMemoryOption(option.substr(strlen("-XX:HeapMaxFree=")).c_str(), 1024);
+ if (size == 0) {
+ if (ignore_unrecognized) {
+ continue;
+ }
+ // TODO: usage
+ LOG(FATAL) << "Failed to parse " << option;
+ return NULL;
+ }
+ parsed->heap_max_free_ = size;
+ } else if (StartsWith(option, "-XX:HeapTargetUtilization=")) {
+ std::istringstream iss(option.substr(strlen("-XX:HeapTargetUtilization=")));
+ double value;
+ iss >> value;
+ // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range.
+ const bool sane_val = iss.good() && (value >= 0.1) && (value <= 0.9);
+ if (!sane_val) {
+ if (ignore_unrecognized) {
+ continue;
+ }
+ LOG(FATAL) << "Invalid option '" << option << "'";
+ return NULL;
+ }
+ parsed->heap_target_utilization_ = value;
} else if (StartsWith(option, "-Xss")) {
size_t size = ParseMemoryOption(option.substr(strlen("-Xss")).c_str(), 1);
if (size == 0) {
@@ -720,6 +759,9 @@
heap_ = new Heap(options->heap_initial_size_,
options->heap_growth_limit_,
+ options->heap_min_free_,
+ options->heap_max_free_,
+ options->heap_target_utilization_,
options->heap_maximum_size_,
options->image_,
options->is_concurrent_gc_enabled_);
diff --git a/src/runtime.h b/src/runtime.h
index ba37f40..a6c662c 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -79,6 +79,9 @@
size_t heap_initial_size_;
size_t heap_maximum_size_;
size_t heap_growth_limit_;
+ size_t heap_min_free_;
+ size_t heap_max_free_;
+ double heap_target_utilization_;
size_t stack_size_;
size_t jni_globals_max_;
size_t lock_profiling_threshold_;