Memory leak in STATSZ on windows if the process cannot read performance counters
Observed behavior
I have a standalone jetstream server running on Windows server 2016. It's runs under a virtual service account which is currently not a member of the system group "Performance Monitor Users". This means it cannot read its own performance counters.
For the initialization in
func ProcUsage(pcpu *float64, rss, vss *int64) error {
...
if initialSample {
if err = initCounters(); err != nil {
return err
}
initialSample = false
}
...some basic logging shows (on test vm, not the prod server):
15:35:43.375 PdhOpenQuery rc=0x0 query=0x1a31e5617e0
15:35:43.376 PdhAddCounterW path="\\Process(nats-pdhtest*)\\ID Process" rc=0x0
15:35:43.377 PdhAddCounterW path="\\Process(nats-pdhtest*)\\% Processor Time" rc=0x0
15:35:43.378 PdhAddCounterW path="\\Process(nats-pdhtest*)\\Working Set - Private" rc=0x0
15:35:43.378 PdhAddCounterW path="\\Process(nats-pdhtest*)\\Virtual Bytes" rc=0x0
15:35:43.378 PdhCollectQueryData rc=0x800007d5
15:35:43.379 initCounters FAILED: pdhCollectQueryData failed - 21474856530x800007D5 is PDH_NO_DATA, the function returns but the handle is not closed with PdhCloseQuery.
So on the next round initCounters() is called again, since initialSample is still true.
Here are the stats from the affected server: It's about 6 Handles per minute.
Measured on the affected server after 27 d 20 h of uptime: 926 MB private bytes, 18 threads, and this handle count in four Task Manager readings:
| Time | Handles | Δ handles | Δ per minute |
|---|---|---|---|
| 13:17 | 241 103 | ||
| 13:21 | 241 130 | +27 | 6.0 |
| 13:25 | 241 156 | +26 | 6.5 |
| 13:30 | 241 181 | +25 | 5.0 |
| 13:40 | 241 241 | +60 | 6.0 |
/varz on that server reports "mem": 0, "cpu": 0 at all times.
I'm open to contributing a fix, if noone from the team has time.
Expected behavior
A failed counter init should not leak memory/handles.
here's a workaround that works:
Add-LocalGroupMember -Group "Performance Monitor Users" -Member "NT SERVICE\<name>"
Restart-Service <name>Server and client version
nats-server v2.14.3
Host environment
Windows Server 2016 Standard, version 1607, build 14393.4104 (handles and memory leak) Windows Server 2022 Standard, build 20348 (memory leak only; no handle leak, maybe MS fixed something here?)
Steps to reproduce
- On Windows, run
nats-server -js -m 8222under an account that cannot read the process performance counters (a virtual service account, any user not in "Performance Monitor Users") GET /varzshows"mem": 0- Watch
(Get-Process nats-server).HandlesandPrivateMemorySize64. On Server 2016 the handle count rises by 6 per minute and the private bytes by about 3.8 KB per leaked query. - To force queries i did:
1..30 | % { iwr http://127.0.0.1:8222/varz | Out-Null; sleep 2 }in powershell. Each request adds one leaked query. Workaroung: add the account to "Performance Monitor Users",/varzreports a realmem, no more growth.
Submission acknowledgment
- I am a human being writing in my own words and not an AI agent. I will not use an AI agent to communicate on my behalf in this issue, either directly or via copy-paste.
Source: nats-io/nats-server