sensors

SNMP Memory & Swap OIDs: hrStorage & UCD Reference

The SNMP OIDs for memory and swap — hrStorageTable rows and UCD memory scalars — with a snmpwalk example and the allocation-unit conversion.

By the SNMP Monitoring team · Reviewed July 2026

Want the memory OID, not a tutorial? Two families cover it: the HOST-RESOURCES storage table (a generic table where RAM and swap are just rows) and the UCD-SNMP memory scalars (dedicated memTotalReal, memAvailSwap and friends). This page is the paste-ready reference for both, with the one conversion that trips everyone up — storage-table values are in allocation units, not bytes.

The "how do I alert without false pages" side is the twin: monitor RAM and monitor swap. Hubs: sensors, all OIDs.

hrStorageTable memory rows

HOST-RESOURCES models every storage area — physical RAM, swap, and each disk — as a row in one table at 1.3.6.1.2.1.25.2.3.1. You pick the RAM or swap row by its hrStorageType, then read the same four columns.

ColumnOIDMeaning
hrStorageDescr1.3.6.1.2.1.25.2.3.1.3Label, e.g. "Physical memory" / "Swap space"
hrStorageAllocationUnits1.3.6.1.2.1.25.2.3.1.4Bytes per unit (the multiplier)
hrStorageSize1.3.6.1.2.1.25.2.3.1.5Total size, in allocation units
hrStorageUsed1.3.6.1.2.1.25.2.3.1.6Used, in allocation units

The two rows you want are typed hrStorageRam (physical memory) and hrStorageVirtualMemory (swap). Don't hard-code a row index — the index for "RAM" isn't fixed across devices. Walk hrStorageType or match on hrStorageDescr, grab that row's index, then read size/used for it. Size and used are Gauge values in units, which is why the next step is mandatory.

UCD memory OIDs

On Net-SNMP boxes there's a friendlier set of scalars under UCD-SNMP-MIB at 1.3.6.1.4.1.2021.4 — already in kB, no row-matching needed:

  • memTotalSwap1.3.6.1.4.1.2021.4.3 — total swap
  • memAvailSwap1.3.6.1.4.1.2021.4.4 — free swap
  • memTotalReal1.3.6.1.4.1.2021.4.5 — total physical RAM
  • memAvailReal1.3.6.1.4.1.2021.4.6 — free physical RAM
  • memTotalFree1.3.6.1.4.1.2021.4.11 — total free (real + swap)

These are scalars (append .0 for a GET), so they skip the table walk entirely. The trade-off: they're a UCD/Net-SNMP thing, so a switch or appliance may not expose them while it still answers the standard hrStorageTable. When both are present, they should broadly agree.

Worked snmpwalk example

Walk the storage table and read the memory rows:

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: 4014276
HOST-RESOURCES-MIB::hrStorageUsed.1 = INTEGER: 3211220
HOST-RESOURCES-MIB::hrStorageDescr.3 = STRING: Swap space
HOST-RESOURCES-MIB::hrStorageAllocationUnits.3 = INTEGER: 1024 Bytes
HOST-RESOURCES-MIB::hrStorageSize.3 = INTEGER: 2097148
HOST-RESOURCES-MIB::hrStorageUsed.3 = INTEGER: 104857

Row .1 is RAM, row .3 is swap. Or grab the UCD scalars directly:

snmpget -v2c -c <RO_string> <host> 1.3.6.1.4.1.2021.4.5.0 1.3.6.1.4.1.2021.4.6.0
UCD-SNMP-MIB::memTotalReal.0 = INTEGER: 4014276 kB
UCD-SNMP-MIB::memAvailReal.0 = INTEGER: 803056 kB

<RO_string> is a placeholder — allowlist the exact prefixes you poll, not the whole enterprise tree.

snmpwalk output of hrStorage RAM and swap rows

Converting to bytes

The storage-table numbers are not bytes. The conversion:

  1. Read hrStorageAllocationUnits for the row (bytes per unit — often 1024 or 4096).
  2. Read hrStorageSize and hrStorageUsed (in units).
  3. Multiply: bytes = value × allocationUnits.

From the walk above, RAM: 4014276 × 1024 = 4,110,618,624 bytes ≈ 3.83 GiB total; used 3211220 × 1024 ≈ 3.06 GiB. Percent used = hrStorageUsed / hrStorageSize × 100 — and because both are in the same units, you can compute the percentage without converting to bytes at all. UCD scalars are already in kB, so multiply by 1024 for bytes; no per-row allocation unit to fetch.

Caveats

A couple of things that make memory numbers lie:

  • Cache and buffers — on Linux, "used" RAM includes cache the kernel will hand back on demand. A box that looks 95% used may have gigabytes of reclaimable cache. hrStorageUsed doesn't separate that out, so don't panic-alert on raw used% alone.
  • Which set is more reliable?hrStorageTable is portable and present on almost everything; UCD scalars are cleaner but Net-SNMP-specific. For cross-vendor consistency, prefer the storage table; on Linux fleets where you control the agent, the UCD scalars are convenient.
  • Row index drift — the index for the RAM row isn't guaranteed stable, so match by type/description each poll rather than assuming .1 is always RAM.

How to monitor RAM & swap (how-to)

Reference ends here; the alerting logic — thresholds, cache-aware used%, swap-in-use warnings — lives on the twins:

Related references: disk OIDs, the full OID catalog, and glossary.

Frequently asked questions

What is the OID for RAM in SNMP?

The portable answer is the hrStorageTable RAM row — pick the row typed hrStorageRam, then read hrStorageSize (1.3.6.1.2.1.25.2.3.1.5) and hrStorageUsed (.6), multiplying by hrStorageAllocationUnits (.4) for bytes. On Net-SNMP hosts, memTotalReal (1.3.6.1.4.1.2021.4.5) and memAvailReal (.6) give it directly in kB.

What OID is swap?

Swap is the hrStorageTable row typed hrStorageVirtualMemory, read the same way as the RAM row. On UCD/Net-SNMP agents, use memTotalSwap (1.3.6.1.4.1.2021.4.3) and memAvailSwap (1.3.6.1.4.1.2021.4.4) for total and free swap in kB.

How do I convert the storage value to bytes?

Multiply the value by the row's allocation units: bytes = hrStorageSize × hrStorageAllocationUnits. The size and used columns are counts of fixed-size blocks (commonly 1024 or 4096 bytes), not bytes themselves. For a used percentage you can skip the conversion, since used ÷ size is already unitless.

hrStorage or UCD memory — which should I use?

Use hrStorageTable for cross-vendor portability; it's implemented almost everywhere. Use the UCD scalars (1.3.6.1.4.1.2021.4) on Net-SNMP/Linux hosts where you want clean kB values without walking a table. Where both exist they should agree closely.

Key takeaways

  • RAM/swap live in the hrStorageTable (1.3.6.1.2.1.25.2.3.1) as rows typed hrStorageRam / hrStorageVirtualMemory.
  • Columns: descr .3, allocationUnits .4, size .5, used .6size/used are in units, not bytes.
  • bytes = value × allocationUnits; used% needs no conversion.
  • UCD scalars under 1.3.6.1.4.1.2021.4 (memTotalReal .5, memAvailReal .6, memTotalSwap .3, memAvailSwap .4) give kB directly on Net-SNMP.
  • Match the RAM row by type/description, not a fixed index; watch cache/buffers before alerting.
  • Procedures: RAM how-to, swap how-to; catalog: sensors/all.

Monitor it from outside the network

SNMP only tells you a box is healthy while something is still asking. ostr.io polls your endpoints externally and fires email + SMS alerts the moment a reading crosses your line — or the agent goes silent.