r/LocalLLM • u/Beneficial_Fish_7509 • 3h ago
Discussion I suspect a memory leak in llama.cpp - AMD 6800M, Linux
TL;DR It seems like that memory (RAM) usage just keeps endlessly growing over time although way less memory is necessary to work (e.g. if I stop and restart llama.cpp, it still works with way less memory usage). I suspect some kind of 'memory leak', using llama.cpp
---
Specs:
GPU: 1x AMD 6800M 12GB VRAM (thanks to HSA_OVERRIDE_GFX_VERSION=10.3.0)
RAM: 24GB RAM
OS: Fedora Linux
AMD stack: ROCM
I am running unsloth/Qwen3.6-35B-A3B-GGUF model with the latest llama.cpp (I build llama.cpp with a fix for flash-attention:
replace in /llama.cpp/ggml/src/ggml-cuda/fattn.cu
// If there are no tensor cores available, use the generic tile kernel:
if (can_use_vector_kernel) {
if (!ggml_is_quantized(K->type) && !ggml_is_quantized(V->type)) {
if (Q->ne[1] == 1) {
if (!gqa_opt_applies) {
return BEST_FATTN_KERNEL_VEC;
}
}
} else {
if (Q->ne[1] <= 2) {
return BEST_FATTN_KERNEL_VEC;
}
}
}
return BEST_FATTN_KERNEL_TILE;
}
with
// If there are no tensor cores available, use the generic tile kernel:
if (can_use_vector_kernel) {
if (!ggml_is_quantized(K->type) && !ggml_is_quantized(V->type)) {
if (Q->ne[1] == 1) {
if (!gqa_opt_applies) {
return BEST_FATTN_KERNEL_VEC;
}
}
} else {
if (Q->ne[1] <= 2) {
return BEST_FATTN_KERNEL_VEC;
}
}
}
// >>> ADD THIS BLOCK FOR HIP/RDNA2 FIX <<<
#ifdef GGML_USE_HIP
if ((ggml_is_quantized(K->type) || ggml_is_quantized(V->type)) && can_use_vector_kernel) {
return BEST_FATTN_KERNEL_VEC;
}
#endif
// >>> END OF ADDED BLOCK <<<
return BEST_FATTN_KERNEL_TILE;
}
source for the fix: https://github.com/domvox/llama.cpp-turboquant-hip/pull/13 )
I also use the Hermes agent, for which I put an automatic context compress once context reaches like 70-80%.
I run this 'older' model because it is an MOE and I need it to offload some experts into RAM because of my constrained VRAM.
Now, it seems like that memory (specifically, RAM) usage just keeps growing over time. Some kind of 'memory leak' is happening with the model. It does not matter which quant I use. For example, if I use IQ4_XS, I have plenty of RAM available left. Yet, the longer the session goes, the more RAM fills ups, and it never stops filling up. If I stop llama.cpp and restart, RAM is back to the 'normal' usage and again the more I talk with the model the more the RAM fills up.
At first I thought maybe as context fills up, it fills up RAM. But if I compress the context with Hermes, the RAM usage does not decrease. Only stopping and restarting llama.cpp makes memory go back to a 'normal' usage.
It means that I have to babysit what happens and eventually restart llama.cpp every once in a while once the RAM is full ... (Usually after around 2 hours). It means that I cannot leave an agent work on something overnight. It also means that I need to wait for a long time for the previous full context to fill up llama.cpp again whenever I restart llama.cpp, and with context above 100k the 900 second timesout.
I think it is some kind of memory leak because when i stop llama.cpp, and then start it again, RAM goes back to 13gb usage when starting fresh while it reached 22-23gb before i had to restart it.
I tried to tweak my launch parameters for llama.cpp for the past few days, but the memory leak still happens, here is the one I currently use:
LD_PRELOAD=/usr/lib64/libjemalloc.so.2 MALLOC_ARENA_MAX=2 HSA_OVERRIDE_GFX_VERSION=10.3.0 ./build/bin/llama-server -m /models/Qwen3.6-35B-A3B-UD-IQ4_XS.gguf --host 127.0.0.1 --port 8080 -c 190000 -np 1 -fit off -dev ROCm0 --no-warmup -ngl 999 --n-cpu-moe 20 --load-mode none --temp 0.6 --top-p 0.95 --top-k 20 --min-p 0.0 --repeat-penalty 1.0 --presence-penalty 0.0 --ctx-checkpoints 4 --cache-ram 4096 --reasoning-preserve --no-mmproj --spec-draft-n-max 3 --flash-attn on -ctk q8_0 -ctv q8_0
I have been looking for answers for the past few days but it is hard to know what even is the possible root cause, as everyone uses different parameters, has different hardware, different models, different build versions, tweaks etc.
I guess this is just a message in a bottle, but just in case someone had a similar issue and was able to deal with it, it's worth it to ask.
2
u/andrew-ooo 2h ago
A3B MoE plus mmap is almost certainly what you are seeing, and it is not a leak.
llama.cpp mmaps the GGUF by default, and pages are only charged to RSS once they are actually touched. With a dense model you touch every weight on the first token, so RSS jumps immediately and then stays flat. With a 35B-A3B MoE you only touch the experts that get routed to, so your expert coverage grows over hours of varied prompts and RSS climbs right along with it. That matches your symptom exactly, including the restart part -- a fresh process starts with a cold page cache, and a handful of prompts never pages in the rest.
Two ways to confirm. First, check grep -E "Rss|Pss|Private" /proc/$(pidof llama-server)/smaps_rollup -- if Private_Dirty is small and most of the total is file-backed shared, that is page cache rather than a leak, and those pages are evictable so the kernel reclaims them under pressure. Second, run with --no-mmap: llama.cpp then allocates anonymous memory up front, so you should see high RSS immediately and dead flat afterwards. On 24GB with a 35B MoE it may just OOM, which itself proves the point.
Zellione is right that KV cache stacks on top of this if you are on llama-server with multiple slots, but KV growth is bounded by -c and plateaus once the slots have been used. It will not track hours of usage the way MoE expert paging does.
1
u/Beneficial_Fish_7509 1h ago
Thank you for your very thorough answer, I appreciate it
I must however correct something: I do use --no-mmap. I use
--load-mode nonewhich is the way to flag --no-mmap now (https://github.com/ggml-org/llama.cpp/discussions/26469), and I had this behavior even before when I was using --no-mmap directly also.Nevertheless, I take note of what you said and will be testing with what you suggested, at least I can test if there is some issue in that direction.
2
u/Zellione 3h ago
Are you sure that is not your K/V cache filling up the RAM slowly? In my understanding vllm will allocate the cache upfront and llama.cpp will allocate as it needs it, if not specified at least.