Hot-Add or Remove Linux Memory with chmem

You need to hand a VM more RAM without a reboot, or pull a block out before a hot-unplug, and chmem does both. This guide uses lsmem to find the right memory block, then walks through a controlled online or offline change. It takes 10 to 15 minutes, and longer if an offline request fails and needs investigating.

Warning: this is a host-level operation. It can change the memory available to workloads, and it can fail if the kernel cannot migrate or release pages.

1. Inspect the memory layout

Start with a read-only inventory. The output gives you the address range, current state, block numbers, zones and the memory block size.

$ lsmem -o RANGE,SIZE,STATE,BLOCK,ZONES
RANGE                                  SIZE  STATE  BLOCK  ZONES
0x0000000000000000-0x0000000007ffffff  128M online      0  None
0x0000000008000000-0x00000000cfffffff  3.1G online   1-25  DMA32
0x0000000100000000-0x000000082fffffff 28.8G online 32-261  Normal

Memory block size:                128M
Total online memory:               32G
Total offline memory:               0B

Your ranges will differ, so do not copy these addresses into a production command. Pick a range or block from your own lsmem output. The requested size or address range must be aligned to the reported Linux memory block size.

Checkpoint: you have written down the exact range, block numbers, state and zone before changing anything. That record is the basis for verification and for an undo attempt.

2. Choose online or offline carefully

Taking memory offline is not the same as deleting its contents. Linux first has to move or release pages, and it can refuse when pages cannot be migrated. Bringing memory online can also fail on a virtual machine when the hypervisor has none left to provide.

Warning: do not run an offline command against a guessed range, and do not test it on a busy host just to see what happens. A successful operation reduces the memory available to applications until you bring the same blocks online again.

3. Enable memory by size

--enable takes a size in MiB by default. Add M or G to make the unit obvious. The documented units use powers of 1024, so 2g means 2 GiB.

$ sudo /usr/sbin/chmem --enable 1024
$ sudo /usr/sbin/chmem --enable 2g

These are examples, not commands to run without checking capacity. When enabling, the program starts with the lowest memory block numbers. If the request can only be partly completed, chmem reports the amount actually changed and exits with status 64.

For a real change, replace SIZE with a size that matches the block layout you inspected:

$ sudo /usr/sbin/chmem --enable SIZE

Verify the result with the same inventory command:

$ lsmem -o RANGE,SIZE,STATE,BLOCK,ZONES

Look for the relevant block or range to show online. Also check the command status immediately after chmem:

$ printf 'chmem exit status: %s\n' "$?"
chmem exit status: 0

4. Disable a known address range

Use the hexadecimal range printed by lsmem to target a physical address range. The end address is the address of the last byte, not a length.

$ sudo /usr/sbin/chmem --disable 0xSTART-0xEND

Replace both placeholders with one complete, aligned range from your own output, and do not leave the literal placeholders in the command. When disabling, chmem starts with the highest memory block numbers, which matters when a size request spans several blocks.

Check the state after the command:

$ lsmem -o RANGE,SIZE,STATE,BLOCK,ZONES
$ printf 'chmem exit status: %s\n' "$?"

The exit codes:

5. Target memory blocks directly

If your change is expressed in block numbers, add --blocks. It accepts a single block or an inclusive first-to-last range.

$ sudo /usr/sbin/chmem --blocks --disable BLOCK
$ sudo /usr/sbin/chmem --blocks --disable FIRST-LAST

For example, --blocks --disable 10 requests block 10, matching the form in the installed manual. Confirm the number exists in your current lsmem output first. A block number is not a byte address, so never mix it with the address-range form.

To undo a successful block-offline operation, enable the same block:

$ sudo /usr/sbin/chmem --blocks --enable BLOCK
$ lsmem -o RANGE,SIZE,STATE,BLOCK,ZONES

Recovery: undo is not guaranteed, because online and offline operations can fail for environmental reasons. If a service is degraded, restore the memory state if you can, then check its logs and the kernel log before repeating the request.

6. Select a memory zone only when needed

Use --zone when you need a particular valid zone and lsmem -o +ZONES shows the range supports it. When bringing memory online, chmem prefers the Movable zone when available. Movable memory is easier to offline again, but it is restricted to migratable pages rather than arbitrary kernel allocations.

$ lsmem -o RANGE,SIZE,STATE,BLOCK,+ZONES
$ sudo /usr/sbin/chmem --enable --zone Movable SIZE

Do not assume every machine offers every zone. The installed command advertises DMA, DMA32, Normal, Highmem, Movable and Device, but the valid choices for a particular range come from that machine's lsmem output. A zone option selects placement. It does not create a zone or override the kernel's suitability checks.

Common traps

Done means