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();
}