Nodejs: MemoryUsage()返回的rss,heapTotal,heapUsed,external的含義和區別

process.memoryUsage()返回當前進程的內存使用情況,但不包括子進程。子進程的內存使用情況需要在子進程中單獨調用process.memoryUsage()。

該函數返回4個參數,含義及差別如下:

  • rss: (Resident Set Size)操作系統分配給進程的總的內存大小。
  • heapTotal:堆的總大小,包括3個部分,
    • 已分配的內存,用於對象的創建和存儲,對應於heapUsed
    • 未分配的但可用於分配的內存
    • 未分配的但不能分配的內存,例如在垃圾收集(GC)之前對象之間的內存碎片
  • heapUsed: 已分配的內存,即堆中所有對象的總大小,是heapTotal的子集。
  • external: 進程使用到的系統鏈接庫所佔用的內存, 如“/usr/lib64/libstdc++.so.6.0.19”

 用如下代碼,打印一個子進程的內存使用情況,可以看出rss大致等於top命令的RES,或者等於ps aux --sort -rss命令中的RSS(單位KB)。另外,主進程的內存只有33M比子進程的內存還小,可見它們的內存佔用情況是獨立統計的。

var showMem = function(){
    var mem = process.memoryUsage();
    var format = function(bytes){
        return (bytes / 1024 / 1024).toFixed(2) + ' MB';
    };
    console.log('Process: heapTotal ' + format(mem.heapTotal) + ' heapUsed ' + format(mem.heapUsed) + ' rss ' + format(mem.rss) + ' external:' + format(mem.external));
    console.log('-----------------------------------------------------------');
};
  setInterval(showMem, 5000);

 控制檯輸出:

top命令: 

 

源碼追蹤:

rss,heapTotal,heapUsed,external都是從V8引擎獲取的,其中,rss是通過調用libuv庫函數int uv_resident_set_memory(size_t* rss)來獲取的。堆細分爲new_space,old_space,code_space,map_space,lo_space (large objects);heapTotal等於堆裏面各個分區的總大小;而heapUsed則等於堆裏面各個分區所有已創建對象的總大小。

src/node.cc

void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
  Environment* env = Environment::GetCurrent(args);

  size_t rss;
  int err = uv_resident_set_memory(&rss);
  if (err) {
    return env->ThrowUVException(err, "uv_resident_set_memory");
  }

  // V8 memory usage
  HeapStatistics v8_heap_stats;
  env->isolate()->GetHeapStatistics(&v8_heap_stats);

  Local<Number> heap_total =
      Number::New(env->isolate(), v8_heap_stats.total_heap_size());
  Local<Number> heap_used =
      Number::New(env->isolate(), v8_heap_stats.used_heap_size());
  Local<Number> external_mem =
      Number::New(env->isolate(),
                  env->isolate()->AdjustAmountOfExternalAllocatedMemory(0));

  Local<Object> info = Object::New(env->isolate());
  info->Set(env->rss_string(), Number::New(env->isolate(), rss));
  info->Set(env->heap_total_string(), heap_total);
  info->Set(env->heap_used_string(), heap_used);
  info->Set(env->external_string(), external_mem);

  args.GetReturnValue().Set(info);
}

deps\v8\src\api.cc

void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
  i::Heap* heap = isolate->heap();
  heap_statistics->total_heap_size_ = heap->CommittedMemory();
  heap_statistics->total_heap_size_executable_ =
      heap->CommittedMemoryExecutable();
  heap_statistics->total_physical_size_ = heap->CommittedPhysicalMemory();
  heap_statistics->total_available_size_ = heap->Available();
  heap_statistics->used_heap_size_ = heap->SizeOfObjects();
  heap_statistics->heap_size_limit_ = heap->MaxReserved();
}

deps/v8/src/heap/heap.cc 

intptr_t Heap::SizeOfObjects() {
  intptr_t total = 0;
  AllSpaces spaces(this);
  for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
    total += space->SizeOfObjects();
  }
  return total;
}

intptr_t Heap::CommittedOldGenerationMemory() {
  if (!HasBeenSetUp()) return 0;

  return old_space_->CommittedMemory() + code_space_->CommittedMemory() +
         map_space_->CommittedMemory() + lo_space_->Size();
}


intptr_t Heap::CommittedMemory() {
  if (!HasBeenSetUp()) return 0;

  return new_space_.CommittedMemory() + CommittedOldGenerationMemory();
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章