Commit 21833093 authored by ager@chromium.org's avatar ager@chromium.org

Introduce a external allocation limit.

If V8 is holding on to a lot of external memory, we attempt to clean
it up even if we do not get an allocation failure.  Since tiny V8
objects can hold on to a lot of external memory, we might run out of
external memory while waiting for a normal allocation failure.
Review URL: http://codereview.chromium.org/155916

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2519 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent be562ee7
...@@ -228,6 +228,31 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) { ...@@ -228,6 +228,31 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
} }
int Heap::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
ASSERT(HasBeenSetup());
int amount = amount_of_external_allocated_memory_ + change_in_bytes;
if (change_in_bytes >= 0) {
// Avoid overflow.
if (amount > amount_of_external_allocated_memory_) {
amount_of_external_allocated_memory_ = amount;
}
int amount_since_last_global_gc =
amount_of_external_allocated_memory_ -
amount_of_external_allocated_memory_at_last_global_gc_;
if (amount_since_last_global_gc > external_allocation_limit_) {
CollectAllGarbage();
}
} else {
// Avoid underflow.
if (amount >= 0) {
amount_of_external_allocated_memory_ = amount;
}
}
ASSERT(amount_of_external_allocated_memory_ >= 0);
return amount_of_external_allocated_memory_;
}
void Heap::SetLastScriptId(Object* last_script_id) { void Heap::SetLastScriptId(Object* last_script_id) {
roots_[kLastScriptIdRootIndex] = last_script_id; roots_[kLastScriptIdRootIndex] = last_script_id;
} }
......
...@@ -85,8 +85,8 @@ GCCallback Heap::global_gc_epilogue_callback_ = NULL; ...@@ -85,8 +85,8 @@ GCCallback Heap::global_gc_epilogue_callback_ = NULL;
// Variables set based on semispace_size_ and old_generation_size_ in // Variables set based on semispace_size_ and old_generation_size_ in
// ConfigureHeap. // ConfigureHeap.
int Heap::young_generation_size_ = 0; // Will be 2 * semispace_size_. int Heap::young_generation_size_ = 0; // Will be 2 * semispace_size_.
int Heap::survived_since_last_expansion_ = 0; int Heap::survived_since_last_expansion_ = 0;
int Heap::external_allocation_limit_ = 0;
Heap::HeapState Heap::gc_state_ = NOT_IN_GC; Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
...@@ -2988,6 +2988,7 @@ bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) { ...@@ -2988,6 +2988,7 @@ bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) {
semispace_size_ = RoundUpToPowerOf2(semispace_size_); semispace_size_ = RoundUpToPowerOf2(semispace_size_);
initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_); initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_);
young_generation_size_ = 2 * semispace_size_; young_generation_size_ = 2 * semispace_size_;
external_allocation_limit_ = 10 * semispace_size_;
// The old generation is paged. // The old generation is paged.
old_generation_size_ = RoundUp(old_generation_size_, Page::kPageSize); old_generation_size_ = RoundUp(old_generation_size_, Page::kPageSize);
......
...@@ -746,7 +746,7 @@ class Heap : public AllStatic { ...@@ -746,7 +746,7 @@ class Heap : public AllStatic {
static Object* CreateSymbol(String* str); static Object* CreateSymbol(String* str);
// Write barrier support for address[offset] = o. // Write barrier support for address[offset] = o.
inline static void RecordWrite(Address address, int offset); static inline void RecordWrite(Address address, int offset);
// Given an address occupied by a live code object, return that object. // Given an address occupied by a live code object, return that object.
static Object* FindCodeObject(Address a); static Object* FindCodeObject(Address a);
...@@ -802,22 +802,7 @@ class Heap : public AllStatic { ...@@ -802,22 +802,7 @@ class Heap : public AllStatic {
// Adjusts the amount of registered external memory. // Adjusts the amount of registered external memory.
// Returns the adjusted value. // Returns the adjusted value.
static int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) { static inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
int amount = amount_of_external_allocated_memory_ + change_in_bytes;
if (change_in_bytes >= 0) {
// Avoid overflow.
if (amount > amount_of_external_allocated_memory_) {
amount_of_external_allocated_memory_ = amount;
}
} else {
// Avoid underflow.
if (amount >= 0) {
amount_of_external_allocated_memory_ = amount;
}
}
ASSERT(amount_of_external_allocated_memory_ >= 0);
return amount_of_external_allocated_memory_;
}
// Allocate unitialized fixed array (pretenure == NON_TENURE). // Allocate unitialized fixed array (pretenure == NON_TENURE).
static Object* AllocateRawFixedArray(int length); static Object* AllocateRawFixedArray(int length);
...@@ -901,6 +886,10 @@ class Heap : public AllStatic { ...@@ -901,6 +886,10 @@ class Heap : public AllStatic {
// every allocation in large object space. // every allocation in large object space.
static int old_gen_allocation_limit_; static int old_gen_allocation_limit_;
// Limit on the amount of externally allocated memory allowed
// between global GCs. If reached a global GC is forced.
static int external_allocation_limit_;
// The amount of external memory registered through the API kept alive // The amount of external memory registered through the API kept alive
// by global handles // by global handles
static int amount_of_external_allocated_memory_; static int amount_of_external_allocated_memory_;
...@@ -1230,7 +1219,7 @@ class KeyedLookupCache { ...@@ -1230,7 +1219,7 @@ class KeyedLookupCache {
// Clear the cache. // Clear the cache.
static void Clear(); static void Clear();
private: private:
inline static int Hash(Map* map, String* name); static inline int Hash(Map* map, String* name);
static const int kLength = 64; static const int kLength = 64;
struct Key { struct Key {
Map* map; Map* map;
......
...@@ -6216,6 +6216,7 @@ THREADED_TEST(NestedHandleScopeAndContexts) { ...@@ -6216,6 +6216,7 @@ THREADED_TEST(NestedHandleScopeAndContexts) {
THREADED_TEST(ExternalAllocatedMemory) { THREADED_TEST(ExternalAllocatedMemory) {
v8::HandleScope outer; v8::HandleScope outer;
v8::Persistent<Context> env = Context::New();
const int kSize = 1024*1024; const int kSize = 1024*1024;
CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize); CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0); CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment