By the SNMP Monitoring team · Reviewed July 2026
Memory pressure is a quiet outage factory: the box still pings, CPU looks fine, and then the OOM killer starts choosing victims. This how-to gets you from “agent answers” to a usable RAM % used signal over SNMP—without turning into the full OID encyclopedia.
OID twin (lookup tables): memory sensors. Parent: server monitoring.
How SNMP reports memory
Two common families on Linux-ish agents:
- HOST-RESOURCES hrStorageTable — rows for RAM, disks, maybe swap; columns for size/used/units/descr
- UCD memory under
1.3.6.1.4.1.2021.4— e.g. memTotalReal.5, memAvailReal.6
Bullets for picking:
- Portable host story → start with hrStorage RAM row
- Need avail/total style UCD objects → poll 2021.4 when present
- Always multiply by allocation units for hrStorage
- Don't mix units across formulas
Full leaf dump: sensors/memory.
Finding the RAM row in hrStorageTable
Base: 1.3.6.1.2.1.25.2.3.1
- descr
.3 - units
.4 - size
.5 - used
.6
RAM rows use hrStorageType hrStorageRam (and descr often like “Physical memory”). Walk descr first, pick the index, then pull size/used/units for that index.
snmpwalk -v2c -c <RO_string> <host> 1.3.6.1.2.1.25.2.3.1.3
HOST-RESOURCES-MIB::hrStorageDescr.1 = STRING: Physical memory
HOST-RESOURCES-MIB::hrStorageDescr.3 = STRING: Virtual memory
HOST-RESOURCES-MIB::hrStorageDescr.10 = STRING: /
Index 1 looks like RAM here—confirm type on your agent, don't assume index stability forever.
Computing % used
Numbered calc for hrStorage:
- Read hrStorageSize, hrStorageUsed, hrStorageAllocationUnits for the RAM index.
- Bytes total = size × units.
- Bytes used = used × units.
- % used = (used ÷ size) × 100.
- Optionally track bytes free = (size − used) × units.
Worked example (units = 1024):
- size = 16333648 → ~16 GB class footprint depending on units
- used = 8921040
- % used ≈ 8921040 / 16333648 × 100 ≈ 54.6%
If size is zero or missing, don't divide—fix the row.
Reading it with snmpwalk
snmpwalk -v2c -c <RO_string> <host> 1.3.6.1.2.1.25.2.3.1
HOST-RESOURCES-MIB::hrStorageDescr.1 = STRING: Physical memory
HOST-RESOURCES-MIB::hrStorageAllocationUnits.1 = INTEGER: 1024 Bytes
HOST-RESOURCES-MIB::hrStorageSize.1 = INTEGER: 16333648
HOST-RESOURCES-MIB::hrStorageUsed.1 = INTEGER: 8921040
UCD alternative:
snmpwalk -v2c -c <RO_string> <host> 1.3.6.1.4.1.2021.4
UCD-SNMP-MIB::memTotalReal.0 = INTEGER: 16333648 kB
UCD-SNMP-MIB::memAvailReal.0 = INTEGER: 6200120 kB
(Exact labels depend on MIB load; numbers are what matter.) Tooling: snmpwalk.

Caveats: cache/buffers vs real free
Linux free shows buffers/cache that can be reclaimed. SNMP hrStorage “used” for RAM often looks higher than the “available” story free prints. That's not always a bug—it's a different definition of used.
Practical stance:
- Alert on sustained high % that correlates with reclaim/OOM pain, not a single sample after a page cache fill
- Watch swap too (swap monitoring)—swap-in is the real “memory hurt” signal
- Don't page every time cache grows
If finance wants “matches free -h,” use UCD fields carefully and document the formula in the runbook.
Reference OIDs & thresholds
Leaves and types: memory OIDs. Alert design: alerts.
Starting policy many teams use:
- Warn ~85–90% used sustained
- Crit ~95%+ sustained or swap climbing hard
- Multi-sample windows—memory spikes during deploys
Tune per workload; JVMs and databases lie differently.
External monitoring
When the host is drowning, you still want something off-box asking for RAM via the storage table. ostr.io can read RAM device name/capacity/usage over external SNMPv2c as part of its metric set—allowlist the storage OIDs, don't expose the world. See external, setup ostr.io.
One contextual product link on this page; the rest is math and walks.
Ops checklist
- Identify RAM index via descr/type
- Poll size, used, units
- Compute % with units
- Graph + multi-sample alert
- Correlate with swap and load
- Re-check after kernel/agent upgrades (indexes shift)
Failure modes
- Alerting on wrong storage row (a disk labeled oddly)
- Forgetting × units → “% used” off by 1024
- Treating cache-heavy used% as emergency
- No swap metric → surprise thrash
Glossary: glossary.
Worked night-shift scenario
Pager: RAM 96% for fifteen minutes on db-03.
- Confirm the alert is the RAM row, not a mislabeled volume.
- Check swap used % and rate of change.
- Check load and CPU—thrash vs pure compute.
- Look for a deploy/backup window in the calendar.
- If swap is climbing and free is critically low, shed load or reboot with intent—not as superstition.
SNMP got you the signal. Runbooks do the rest. Without swap + duration, you'd have paged on cache fill after a warm-up every night.
What not to put on this page
Full UCD leaf catalogs, every vendor enterprise memory OID, and thirty screenshots of MIB browsers. That's sensors/memory and vendor MIBs. Here: find row → compute % → alert → optionally externalize.
If hrStorageRam is missing, say so in the device note and fall back to UCD or vendor objects after a lab walk—don't invent leaves.
Threshold starting points (not gospel)
| Workload | Warn used % | Crit used % | Also watch |
|---|---|---|---|
| General VM | ~85 | ~95 | swap |
| JVM host | ~80 | ~90 | GC / swap |
| DB buffer-heavy | tune high | tune with DBA | swap + disk |
Numbers are starting guns. If warn fires daily and nobody acts, raise the bar or fix capacity—alert fatigue is a monitoring bug. Write the final numbers into the service runbook so 3 a.m. you is not guessing under heavy pressure at night.
Cross-check with CPU and load when memory pressure presents as “everything is slow.”
UCD path recap when hrStorage fights you: base 1.3.6.1.4.1.2021.4, memTotalReal .5, memAvailReal .6. Still document units (often kB in descriptions) before graphing. And remember ostr.io-style external checks that read the storage table for RAM capacity/usage need those OIDs in the allowlist—name them explicitly in the ticket when you open the firewall.
Frequently asked questions
What OID is memory usage in SNMP?
Use hrStorage used/size under 1.3.6.1.2.1.25.2.3.1 for the RAM row, or UCD 1.3.6.1.4.1.2021.4.6 / .5 style total/avail when present. Twin page lists details: sensors/memory.
How do I calculate RAM % used?
(hrStorageUsed ÷ hrStorageSize) × 100 for that row. Convert to bytes with × hrStorageAllocationUnits when you need GB.
Does SNMP show free memory?
Derive free as (size − used) × units, or use UCD avail objects when exposed.
Why does SNMP memory differ from free?
Different accounting of cache/buffers and which pools count as “used.” Compare trends, not single-sample equality.
Key takeaways
- RAM via hrStorageTable (+ optional UCD 2021.4).
- % used = used/size; bytes need allocation units.
- Mind cache vs pressure; watch swap.
- OID reference: sensors/memory.
- Optional off-box: ostr.io.