使用Node.js開發後端程式的時候,在某些情況下可能會需要查看運行環境還剩下多少的記憶體來決定是否繼續進行工作,那麼該如何使用Node.js來獲取運行環境的記憶體資訊呢?
os.totalmem和os.freemem
Node.js內建的os
模組其實就有提供totalmem
和freemem
函數來分別抓取作業系統的記憶體總量和閒置的記憶體,用法如下:
const os = require("os");
console.log(os.freemem()); // 8488792064 (bytes)
console.log(os.totalmem()); // 33638309888 (bytes)
然而在實際應用上,只知道記憶體總量和閒置的記憶體是沒什麼用處的。因為現在的作業系統都傾向利用更多沒有使用到的記憶體來做快取和緩衝,來加速非主記憶體裝置的I/O速度,當作業系統需要分配超過閒置記憶體大小的記憶體給行程使用時,不足的部份就會藉由釋放被用來做快取和緩衝的記憶體區塊來補足。所以透過os.freemem()
所得到的閒置記憶體總是比作業系統實際的「可用記憶體」還要來得少很多,而且也愈來愈沒有參考價值了。
在Linux系統上,常會使用free
或是top
指令來查看作業系統的記憶體資訊。例如:
total used free shared buff/cache available Mem: 33638309888 6050537472 8488792064 185831424 19098980352 26580381696 置換: 0 0 0
其中選項「-b」表示記憶體大小的單位為位元組(byte)。而且可以看到光是記憶體資訊就有分total
、used
、free
、shared
、buff/cache
、available
這幾個欄位,甚至還有「Mem(主記憶體RAM)」和「置換(Swap)」兩列,這比起Node.js內建提供的totalmem
和freemem
還要多了很多個項目能參考。
先來看主記憶體的部份,total
的部份指得就是主記憶體或是的大小,其數值會和Node.js內建的os
模組的totalmem
相同。used
的部份指得是已被使用的記憶體,包含共享記憶體,但不包含被用來做快取和緩衝的部份。free
是完全沒被使用到的閒置記憶體,其數值會和Node.js內建的os
模組的「freemem」相同。shared
是可供不同行程(Process)一起使用的共享記憶體。buff/cache
是快取和緩衝還有用來管理其他記憶體的Slab快取(Slab Allocator)所佔用的記憶體。available
則才是作業系統目前真正的「可用記憶體」。
再來是置換空間(Swap)的部份,因為置換空間是把次級儲存器(Secondary Storage)或是外部儲存器(External Storage)作為記憶體使用,速度不快,通常會是在主記憶體不夠用的情況下才會去使用,但著實可以成為作業系統可用記憶體的一部份。因此在計算作業系統真正最高可以配置的可用記憶體大小的時候,會把主記憶體的available
和置換空間的free
相加,也就是說,如果行程需要配置的記憶體大小超過這個值的話,作業系統將會因為沒有足夠的記憶體能夠使用而導致當機。
回到Node.js的主題上,那麼要如何使用Node.js來得知這些詳細的記憶體資訊呢?Linux系統的話,可以透過讀取/proc/meminfo
這個檔案來取得即時的記憶體資訊。順帶一提,free
和top
指令在程式實作上其實也是去讀取/proc/meminfo
再將資訊編排出來。
使用cat
指令來讀取/proc/meminfo
檔案:
MemTotal: 32849912 kB MemFree: 7000712 kB MemAvailable: 24702036 kB Buffers: 50048 kB Cached: 17159880 kB SwapCached: 0 kB Active: 19296416 kB Inactive: 4682504 kB Active(anon): 6772572 kB Inactive(anon): 204088 kB Active(file): 12523844 kB Inactive(file): 4478416 kB Unevictable: 1016 kB Mlocked: 1016 kB SwapTotal: 0 kB SwapFree: 0 kB Dirty: 896 kB Writeback: 0 kB AnonPages: 5993088 kB Mapped: 1352728 kB Shmem: 207672 kB Slab: 1506992 kB SReclaimable: 1169828 kB SUnreclaim: 337164 kB KernelStack: 25180 kB PageTables: 99816 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 16424956 kB Committed_AS: 20239936 kB VmallocTotal: 34359738367 kB VmallocUsed: 0 kB VmallocChunk: 0 kB HardwareCorrupted: 0 kB AnonHugePages: 2236416 kB ShmemHugePages: 0 kB ShmemPmdMapped: 0 kB CmaTotal: 0 kB CmaFree: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 4365648 kB DirectMap2M: 29093888 kB DirectMap1G: 1048576 kB
透過/proc/meminfo
檔案可以得到非常詳細的記憶體資訊,只要在Node.js中使用檔案相關的模組去讀取/proc/meminfo
的內容回來,再去解析(parse)有用的資訊即可。當然,也可以直接用底下將要介紹的模組。
node-meminfo
node-meminfo
是一個使用Node.js 8之後才支援的N-API所開發的模組,使用Rust語言來讀取Linux作業統中的/proc/meminfo
所儲存的記憶體資訊。
npmjs.com
npm 安裝指令
使用方法
使用模組提供的meminfo
函數可以完整地取得/proc/meminfo
所儲存的記憶體資訊,用法如下:
import { meminfo } from "node-meminfo";
console.log(meminfo());
/*
{
MemTotal: 33638309888,
MemFree: 6813110272,
MemAvailable: 25217355776,
Buffers: 45658112,
Cached: 17956536320,
SwapCached: 0,
Active: 20752044032,
Inactive: 4362379264,
'Active(anon)': 7117885440,
'Inactive(anon)': 199598080,
'Active(file)': 13634158592,
'Inactive(file)': 4162781184,
Unevictable: 1343488,
Mlocked: 1343488,
SwapTotal: 0,
SwapFree: 0,
Dirty: 1826816,
Writeback: 0,
AnonPages: 6723411968,
Mapped: 1297338368,
Shmem: 205258752,
Slab: 1387651072,
SReclaimable: 1089368064,
SUnreclaim: 298283008,
KernelStack: 23089152,
PageTables: 84766720,
NFS_Unstable: 0,
Bounce: 0,
WritebackTmp: 0,
CommitLimit: 16819154944,
Committed_AS: 18899087360,
VmallocTotal: 35184372087808,
VmallocUsed: 0,
VmallocChunk: 0,
HardwareCorrupted: 0,
AnonHugePages: 3951034368,
ShmemHugePages: 0,
ShmemPmdMapped: 0,
CmaTotal: 0,
CmaFree: 0,
HugePages_Total: 0,
HugePages_Free: 0,
HugePages_Rsvd: 0,
HugePages_Surp: 0,
Hugepagesize: 2097152,
DirectMap4k: 3071623168,
DirectMap2M: 26895974400,
DirectMap1G: 5368709120
}
*/
這裡要注意的是,模組取得的數值所用的單位是位元組(byte),而不是/proc/meminfo
原先的KB。
另外,若您像筆者一樣比較習慣free
指令所提供的資訊格式的話,也可以使用模組提供的free
函數來取得記憶體資訊,用法如下:
import { meminfo } from "node-meminfo";
console.log(free());
/*
{
mem: {
total: 33638309888,
used: 7504060416,
free: 6697676800,
shared: 211382272,
buff: 45658112,
cache: 19390914560,
available: 25142546432
},
swap: {
total: 0,
used: 0,
free: 0,
cache: 0
}
}
*/