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