Same RAM on paper, so why does the app use more on KVM?
free.
KVM is full virtualization. Your VPS boots its own kernel inside a virtual machine, and that kernel lives inside your RAM allocation. Kernel code, slab caches (memory the kernel uses for its internal objects), page tables, and kernel threads all come out of the same pool your app uses. Depending on the kernel and boot parameters, some memory may also be reserved at boot, so MemTotal inside the guest can be lower than the plan says. None of this is waste. It is overhead that used to sit on someone else's books.
The OS template matters too. A fresh KVM image can run services the old container never had, depending on the distro and how the image was built. It is worth listing running services after the move rather than assuming the base system is as lean as before.
What was burst memory, and was my app quietly depending on it?
cat /proc/user_beancounters shows held and maximum values per resource, plus a failcnt column that counts how many times a limit was hit. Look at peak usage, not the plan name, when you size the new VPS. Database settings deserve the most attention here. If InnoDB was sized generously on the old box, the article on checking whether your InnoDB buffer pool size fits the server walks through right-sizing it.
Why does free suddenly show so much buff/cache?
free output often looked cleaner than it really was.
So a KVM guest showing large buff/cache and a small free column is usually healthy. The number to watch is available (or MemAvailable in /proc/meminfo), which estimates how much memory can be handed to applications without swapping. If that misunderstanding sounds familiar, there is a separate piece on why a small free column in free -m does not mean RAM is running out.
Why is swap being used when RAM is not full?
vm.swappiness setting controls how willing the kernel is to do this. It defaults to 60 on most distributions, but check yours. Some swap in use with no ongoing activity is normal and not worth worrying about.
What matters is sustained swap traffic. In vmstat, the si and so columns show memory swapped in and out per second. If they stay above zero for minutes while available keeps shrinking, the VM is under real pressure and the site will feel slow, because every swapped page now waits on disk I/O. The other clear signal is the kernel OOM killer. Inside your own VM it picks a process and kills it, which on a web server is often MySQL.
BASH
# Read-only checks, safe to run on the new KVM VPS
free -m
grep -E 'MemTotal|MemAvailable|Committed_AS|SwapTotal|SwapFree' /proc/meminfo
swapon --show
cat /proc/sys/vm/swappiness
# 6 samples, 5 seconds apart; watch the si and so columns
vmstat 5 6
# Look for past OOM kills (use dmesg if journald is not available)
journalctl -k | grep -i 'out of memory'Committed_AS is worth a glance too. It shows how much memory processes have asked for, which can be well above what they currently use. If it sits far above MemTotal, a traffic spike that makes those processes touch their allocations can tip the VM into swapping.
How should I size RAM and swap on the new VPS?
chmod 600, format it with mkswap, enable it with swapon, and add it to /etc/fstab so it survives a reboot. The exact way to create the file depends on the filesystem. fallocate works on many setups, some need dd, and btrfs needs extra steps, so check your distro's documentation first. If you change vm.swappiness, do it after watching real behavior for a while, and remember that lowering it does not create memory. It only changes which pages the kernel gives up first.
A practical way to approach the first week after a move: check available and si/so during normal traffic and again at peak, scan the kernel log for OOM kills, and compare against what the old container really used. If available stays comfortable and swap activity stays quiet, the higher usage figure is just KVM being honest about the kernel and cache it now carries. If not, resize the app or the plan, not the swap file.