Introduce a external allocation limit.
authorager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 22 Jul 2009 10:01:25 +0000 (10:01 +0000)
committerager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 22 Jul 2009 10:01:25 +0000 (10:01 +0000)
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

src/heap-inl.h
src/heap.cc
src/heap.h
test/cctest/test-api.cc

index 36c6f4bfa2c54955cb120a2372e0926893438c8b..d27f14f1aff12d44a07a493501639e7cca280446 100644 (file)
@@ -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) {
   roots_[kLastScriptIdRootIndex] = last_script_id;
 }
index cad175587fc1870e97c680d1297a4adc23925633..213eec5abd9f17929b8d5bf5e10552339670ee58 100644 (file)
@@ -85,8 +85,8 @@ GCCallback Heap::global_gc_epilogue_callback_ = NULL;
 // Variables set based on semispace_size_ and old_generation_size_ in
 // ConfigureHeap.
 int Heap::young_generation_size_ = 0;  // Will be 2 * semispace_size_.
-
 int Heap::survived_since_last_expansion_ = 0;
+int Heap::external_allocation_limit_ = 0;
 
 Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
 
@@ -2988,6 +2988,7 @@ bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) {
   semispace_size_ = RoundUpToPowerOf2(semispace_size_);
   initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_);
   young_generation_size_ = 2 * semispace_size_;
+  external_allocation_limit_ = 10 * semispace_size_;
 
   // The old generation is paged.
   old_generation_size_ = RoundUp(old_generation_size_, Page::kPageSize);
index 55a66bccd178dd8e0fa0e94708960c6bb119564c..4e2c64cd418f826d6d32ebece64b8b991c3dde25 100644 (file)
@@ -746,7 +746,7 @@ class Heap : public AllStatic {
   static Object* CreateSymbol(String* str);
 
   // 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.
   static Object* FindCodeObject(Address a);
@@ -802,22 +802,7 @@ class Heap : public AllStatic {
 
   // Adjusts the amount of registered external memory.
   // Returns the adjusted value.
-  static 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_;
-  }
+  static inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
 
   // Allocate unitialized fixed array (pretenure == NON_TENURE).
   static Object* AllocateRawFixedArray(int length);
@@ -901,6 +886,10 @@ class Heap : public AllStatic {
   // every allocation in large object space.
   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
   // by global handles
   static int amount_of_external_allocated_memory_;
@@ -1230,7 +1219,7 @@ class KeyedLookupCache {
   // Clear the cache.
   static void Clear();
  private:
-  inline static int Hash(Map* map, String* name);
+  static inline int Hash(Map* map, String* name);
   static const int kLength = 64;
   struct Key {
     Map* map;
index e6849be83bc198f80b68e4d78e60887c2000669c..806e7116be106ac7c95c81bfd89d8ad153f67dfd 100644 (file)
@@ -6216,6 +6216,7 @@ THREADED_TEST(NestedHandleScopeAndContexts) {
 
 THREADED_TEST(ExternalAllocatedMemory) {
   v8::HandleScope outer;
+  v8::Persistent<Context> env = Context::New();
   const int kSize = 1024*1024;
   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);