@@ -1562,14 +1562,31 @@ size_t Environment::NearHeapLimitCallback(void* data,
15621562 size_t num_heap_spaces = env->isolate ()->NumberOfHeapSpaces ();
15631563 for (size_t i = 0 ; i < num_heap_spaces; ++i) {
15641564 env->isolate ()->GetHeapSpaceStatistics (&stats, i);
1565+
1566+ Debug (env,
1567+ DebugCategory::DIAGNOSTICS,
1568+ " %s space_size = %" PRIu64 " , "
1569+ " space_used_size = %" PRIu64 " , "
1570+ " space_available_size = %" PRIu64 " , "
1571+ " physical_space_size = %" PRIu64 " \n " ,
1572+ stats.space_name (),
1573+ static_cast <uint64_t >(stats.space_size ()),
1574+ static_cast <uint64_t >(stats.space_used_size ()),
1575+ static_cast <uint64_t >(stats.space_available_size ()),
1576+ static_cast <uint64_t >(stats.physical_space_size ()));
1577+
1578+ // space_size() returns the allocated size of a given space,
1579+ // we use this to calculate the new limit because V8 also
1580+ // uses the allocated size to determine whether it should crash.
15651581 if (strcmp (stats.space_name (), " new_space" ) == 0 ||
15661582 strcmp (stats.space_name (), " new_large_object_space" ) == 0 ) {
1567- young_gen_size += stats.space_used_size ();
1583+ young_gen_size += stats.space_size ();
15681584 } else {
1569- old_gen_size += stats.space_used_size ();
1585+ old_gen_size += stats.space_size ();
15701586 }
15711587 }
15721588
1589+ size_t total_size = young_gen_size + old_gen_size;
15731590 Debug (env,
15741591 DebugCategory::DIAGNOSTICS,
15751592 " max_young_gen_size=%" PRIu64 " , "
@@ -1579,21 +1596,15 @@ size_t Environment::NearHeapLimitCallback(void* data,
15791596 static_cast <uint64_t >(max_young_gen_size),
15801597 static_cast <uint64_t >(young_gen_size),
15811598 static_cast <uint64_t >(old_gen_size),
1582- static_cast <uint64_t >(young_gen_size + old_gen_size ));
1599+ static_cast <uint64_t >(total_size ));
15831600
15841601 uint64_t available = GuessMemoryAvailableToTheProcess ();
15851602 // TODO(joyeecheung): get a better estimate about the native memory
15861603 // usage into the overhead, e.g. based on the count of objects.
1587- uint64_t estimated_overhead = max_young_gen_size;
1588- Debug (env,
1589- DebugCategory::DIAGNOSTICS,
1590- " Estimated available memory=%" PRIu64 " , "
1591- " estimated overhead=%" PRIu64 " \n " ,
1592- static_cast <uint64_t >(available),
1593- static_cast <uint64_t >(estimated_overhead));
1594-
1595- // This might be hit when the snapshot is being taken in another
1596- // NearHeapLimitCallback invocation.
1604+ uint64_t estimated_overhead = young_gen_size;
1605+ // The new limit must be higher than current_heap_limit or V8 might
1606+ // crash.
1607+ uint64_t minimun_new_limit = static_cast <uint64_t >(current_heap_limit + 1 );
15971608 // When taking the snapshot, objects in the young generation may be
15981609 // promoted to the old generation, result in increased heap usage,
15991610 // but it should be no more than the young generation size.
@@ -1602,33 +1613,56 @@ size_t Environment::NearHeapLimitCallback(void* data,
16021613 // new limit, so in a heap with unbounded growth the isolate
16031614 // may eventually crash with this new limit - effectively raising
16041615 // the heap limit to the new one.
1616+ uint64_t estimated_space_needed =
1617+ std::max (estimated_overhead + total_size, minimun_new_limit);
1618+
1619+ Debug (env,
1620+ DebugCategory::DIAGNOSTICS,
1621+ " Estimated available memory=%" PRIu64 " , "
1622+ " estimated overhead=%" PRIu64 " \n "
1623+ " estimated space needed=%" PRIu64 " \n " ,
1624+ static_cast <uint64_t >(available),
1625+ static_cast <uint64_t >(estimated_overhead),
1626+ static_cast <uint64_t >(estimated_space_needed));
1627+
1628+ // This might be hit when the snapshot is being taken in another
1629+ // NearHeapLimitCallback invocation.
1630+ // TODO(joyeecheung): turn this into
1631+ // DCHECK(!env->is_processing_heap_limit_callback_)
1632+ // when V8 ensures that the callback can't be nested.
16051633 if (env->is_processing_heap_limit_callback_ ) {
1606- size_t new_limit = current_heap_limit + max_young_gen_size;
16071634 Debug (env,
16081635 DebugCategory::DIAGNOSTICS,
16091636 " Not generating snapshots in nested callback. "
16101637 " new_limit=%" PRIu64 " \n " ,
1611- static_cast <uint64_t >(new_limit ));
1612- return new_limit ;
1638+ static_cast <uint64_t >(estimated_space_needed ));
1639+ return estimated_space_needed ;
16131640 }
16141641
16151642 // Estimate whether the snapshot is going to use up all the memory
16161643 // available to the process. If so, just give up to prevent the system
16171644 // from killing the process for a system OOM.
1618- if (estimated_overhead > available) {
1645+ if (estimated_space_needed > available) {
16191646 Debug (env,
16201647 DebugCategory::DIAGNOSTICS,
16211648 " Not generating snapshots because it's too risky.\n " );
16221649 env->isolate ()->RemoveNearHeapLimitCallback (NearHeapLimitCallback,
16231650 initial_heap_limit);
1624- // The new limit must be higher than current_heap_limit or V8 might
1625- // crash.
1626- return current_heap_limit + 1 ;
1651+
1652+ return minimun_new_limit;
16271653 }
16281654
1629- // Take the snapshot synchronously.
1655+ env-> initial_heap_limit_ = initial_heap_limit;
16301656 env->is_processing_heap_limit_callback_ = true ;
1657+ env->isolate ()->RequestInterrupt (TakeSnapshotInNearHeapLimitCallback, env);
1658+ // The new limit must be higher than current_heap_limit or V8 might
1659+ // crash.
1660+ return estimated_space_needed;
1661+ }
16311662
1663+ void Environment::TakeSnapshotInNearHeapLimitCallback (v8::Isolate* isolate,
1664+ void * data) {
1665+ Environment* env = static_cast <Environment*>(data);
16321666 std::string dir = env->options ()->diagnostic_dir ;
16331667 if (dir.empty ()) {
16341668 dir = env->GetCwd ();
@@ -1640,8 +1674,12 @@ size_t Environment::NearHeapLimitCallback(void* data,
16401674
16411675 // Remove the callback first in case it's triggered when generating
16421676 // the snapshot.
1677+ // TODO(joyeecheung): when V8 ensures that the callback can't be nested,
1678+ // we can simply remove the callback when env->heap_limit_snapshot_taken_
1679+ // reaches env->options_->heap_snapshot_near_heap_limit at the
1680+ // end of this interrupt.
16431681 env->isolate ()->RemoveNearHeapLimitCallback (NearHeapLimitCallback,
1644- initial_heap_limit );
1682+ env-> initial_heap_limit_ );
16451683
16461684 heap::WriteSnapshot (env, filename.c_str ());
16471685 env->heap_limit_snapshot_taken_ += 1 ;
@@ -1659,10 +1697,6 @@ size_t Environment::NearHeapLimitCallback(void* data,
16591697 env->isolate ()->AutomaticallyRestoreInitialHeapLimit (0.95 );
16601698
16611699 env->is_processing_heap_limit_callback_ = false ;
1662-
1663- // The new limit must be higher than current_heap_limit or V8 might
1664- // crash.
1665- return current_heap_limit + 1 ;
16661700}
16671701
16681702inline size_t Environment::SelfSize () const {
0 commit comments