fix: report actual memory without cache

This commit is contained in:
Codex
2026-05-04 14:52:31 +00:00
parent a16fedd9e4
commit 3207b9ecb1
6 changed files with 27 additions and 14 deletions
+4 -4
View File
@@ -451,7 +451,7 @@ function NodeMonitorPage({ nodes, systemStatuses, onRaw, refresh }: AnyRecord) {
h("div", { className: "docker-meta" },
h("span", null, `${cpu.cores || 0} CPU cores`),
h("span", null, `load ${asNumber(cpu.load1).toFixed(2)} / ${asNumber(cpu.load5).toFixed(2)} / ${asNumber(cpu.load15).toFixed(2)}`),
h("span", null, `memory ${fmtBytes(memory.usedBytes)} / ${fmtBytes(memory.totalBytes)}`),
h("span", null, `memory actual ${fmtBytes(memory.usedBytes)} / ${fmtBytes(memory.totalBytes)}`),
h("span", null, `disk ${fmtBytes(disk.usedBytes)} / ${fmtBytes(disk.totalBytes)}`),
),
),
@@ -459,12 +459,12 @@ function NodeMonitorPage({ nodes, systemStatuses, onRaw, refresh }: AnyRecord) {
),
h("div", { className: "monitor-chart-grid" },
h(MetricChart, { title: "CPU", metricKey: "cpuPercent", current: cpu.percent, points, detail: `${cpu.cores || 0} cores / load ${asNumber(cpu.load1).toFixed(2)}`, tone: "cpu", testId: "metric-chart-cpu" }),
h(MetricChart, { title: "Memory", metricKey: "memoryPercent", current: memory.percent, points, detail: `${fmtBytes(memory.usedBytes)} used / ${fmtBytes(memory.availableBytes)} free`, tone: "memory", testId: "metric-chart-memory" }),
h(MetricChart, { title: "Memory", metricKey: "memoryPercent", current: memory.percent, points, detail: `${fmtBytes(memory.usedBytes)} actual / ${fmtBytes(memory.cacheBytes)} cache excluded`, tone: "memory", testId: "metric-chart-memory" }),
h(MetricChart, { title: "Disk", metricKey: "diskPercent", current: disk.percent, points, detail: `${disk.path || "/"} mounted ${disk.mount || "--"}`, tone: "disk", testId: "metric-chart-disk" }),
),
h("div", { className: "monitor-summary-grid" },
h(MetricCard, { label: "CPU 当前", value: fmtPercent(cpu.percent), hint: `history ${points.length} samples`, tone: "ok" }),
h(MetricCard, { label: "内存已用", value: fmtBytes(memory.usedBytes), hint: fmtPercent(memory.percent) }),
h(MetricCard, { label: "实际内存", value: fmtBytes(memory.usedBytes), hint: `${fmtPercent(memory.percent)} 不含缓存` }),
h(MetricCard, { label: "硬盘已用", value: fmtBytes(disk.usedBytes), hint: fmtPercent(disk.percent) }),
h(MetricCard, { label: "更新时间", value: fmtDate(active.systemUpdatedAt || current.collectedAt), hint: active.providerId }),
),
@@ -475,7 +475,7 @@ function NodeMonitorPage({ nodes, systemStatuses, onRaw, refresh }: AnyRecord) {
h(Panel, { title: "采样说明", eyebrow: "Retention" },
h("div", { className: "monitor-note-list" },
h("article", null, h("b", null, "CPU"), h("span", null, "从 /proc/stat 计算相邻采样差值,首个采样用 load/cores 近似")),
h("article", null, h("b", null, "Memory"), h("span", null, "使用 MemTotal MemAvailable 计算已用比例")),
h("article", null, h("b", null, "Memory"), h("span", null, "实际内存 = MemTotal - MemFree - Buffers - Cached - SReclaimable + Shmem,不把 page cache / buffer 计入占用")),
h("article", null, h("b", null, "Disk"), h("span", null, "使用 df -PB1 对配置路径采样,默认监控根文件系统")),
),
),
+16 -3
View File
@@ -380,16 +380,29 @@ async function collectSystemStatus(): Promise<SystemStatusSnapshot> {
errors.push({ source: "proc.stat", error: error instanceof Error ? error.message : String(error) });
}
let memory: Record<string, JsonValue> = { totalBytes: 0, usedBytes: 0, availableBytes: 0, percent: 0 };
let memory: Record<string, JsonValue> = { totalBytes: 0, usedBytes: 0, availableBytes: 0, cacheBytes: 0, percent: 0, mode: "actual_without_cache" };
try {
const mem = readMemInfo();
const totalBytes = mem.MemTotal ?? 0;
const availableBytes = mem.MemAvailable ?? mem.MemFree ?? 0;
const usedBytes = Math.max(0, totalBytes - availableBytes);
const freeBytes = mem.MemFree ?? 0;
const buffersBytes = mem.Buffers ?? 0;
const cachedBytes = mem.Cached ?? 0;
const reclaimableBytes = mem.SReclaimable ?? 0;
const shmemBytes = mem.Shmem ?? 0;
const cacheBytes = Math.max(0, buffersBytes + cachedBytes + reclaimableBytes - shmemBytes);
const usedBytes = Math.max(0, totalBytes - freeBytes - cacheBytes);
const availableBytes = mem.MemAvailable ?? Math.max(0, freeBytes + cacheBytes);
memory = {
mode: "actual_without_cache",
totalBytes,
usedBytes,
availableBytes,
freeBytes,
cacheBytes,
buffersBytes,
cachedBytes,
reclaimableBytes,
shmemBytes,
percent: totalBytes > 0 ? clampPercent((usedBytes / totalBytes) * 100) : 0,
};
} catch (error) {