From c5b36eac244bac04c08adaf9933ea4d880b4f4c4 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 18 Sep 2026 11:08:14 +0600 Subject: [PATCH] [2026-09-18] eagle: family/tech/t610-hw-metrics-addon.md --- family/tech/t610-hw-metrics-addon.md | 102 +++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/family/tech/t610-hw-metrics-addon.md b/family/tech/t610-hw-metrics-addon.md index 8b9b1ded..071d4ed2 100644 --- a/family/tech/t610-hw-metrics-addon.md +++ b/family/tech/t610-hw-metrics-addon.md @@ -324,6 +324,108 @@ Device — `t610`, имя сущности в первой редакции бы --- +## 10a. 🔍 Разбор 2026-09-18: «free RAM упала до 380 МБ, used растёт — течёт?» + +> **Вопрос Alex:** почему `free RAM != available − used`, почему `free` скачкообразно упала +> уже до 380 МБ, а `used` медленно растёт. Гипотеза: «походу течёт что-то». +> +> **Ответ: течи нет.** Это **рост файлового кэша (`Cached`)** + **нормальное поведение Linux**. +> `MemAvailable` за 23 часа почти не изменился: **2 554 → 2 508 МБ (−46 МБ, −1.8 %)**. + +### 10a.1. Почему `free != available − used` — это НЕ баг датчиков + +`free` и `used` меряют **разные вещи**, они и не должны сходиться: + +| Датчик | Формула | Смысл | +|---|---|---| +| `ram_free` | `MemFree` | память, не занятая **ничем вообще** (даже кэшем) | +| `ram_used` | `MemTotal − MemAvailable` | реально занято приложениями (ядро **уже вычло** кэш, который можно отдать) | +| `ram_available` | `MemAvailable` | сколько **дадут**, если приложению попросить (free + отдаваемый кэш) | + +Тождество: `MemTotal = MemFree + Cached + Buffers + AnonPages + Slab + …` +`MemAvailable ≈ MemFree + Cached + Buffers − несжимаемая часть`. + +Проверено живой строкой лога: +``` +free(392588) + cached(1925740) + swapfree(1145356) = 3 463 684 +MemAvailable = 2 508 852 +разница = 954 832 kB ≈ 932 МБ +``` +**Разница 932 МБ — это `Active(file)` кэша, который ядро НЕ считает «легко отдаваемым».** +Значит `available − used` и `free` **обязаны** расходиться на сотни МБ. Расхождение — **норма, не дефект**. + +### 10a.2. Почему `free` упала ступеньками — растёт `Cached` + +Часовые средние из `/share/ha-metrics/hw-2026-09.log` (23 ч аптайма): + +| Час (UTC) | `Cached` МБ | `MemFree` МБ | `MemAvailable` МБ | +|---|---|---|---| +| 09-17 06 | 1 621 | 769 | 2 493 | +| 09-17 12 | 1 637 | 713 | 2 478 | +| 09-17 21 | 1 665 | 653 | 2 458 | +| **09-17 22** | **1 752 (+87)** | **554 (−99)** | 2 456 | +| **09-18 04** | **1 840 (+88)** | **448 (−106)** | 2 453 | +| 09-18 05 | 1 879 | 381 | 2 447 | + +> 🔑 **Механизм:** `MemFree` падает **ступеньками ровно тогда**, когда растёт `Cached`. +> Числа сходятся с точностью до десятков МБ: `−87 МБ free` ↔ `+87 МБ cached` (22:00), +> `−106 МБ free` ↔ `+88 МБ cached` (04:00). +> **Это не утечка — это страничный кэш.** Файловая система читает что-то новое (SQLite-БД +> 105 МБ + WAL, логи, бэкапы), ядро оставляет страницы в памяти «на всякий случай». +> **Ступеньки = моменты активного чтения файлов** (запись в БД, бэкап-джоб, дневной цикл recorder). + +### 10a.3. Почему `used` медленно растёт — это тоже норма + +`ram_used` (МБ): 896 → 899 → … → 957 за 23 ч. **+61 МБ за сутки ≈ 2.6 МБ/ч.** + +`used = MemTotal − MemAvailable`, а `MemAvailable` падает не от забивания памяти, +а от **снижения «легко отдаваемой» доли кэша**: чем больше `Active(file)` (страницы, к которым +недавно обращались), тем меньше ядро готово отдать «прямо сейчас». + +> ✅ **Диагностический признак НАСТОЯЩЕЙ течи** (которого здесь **нет**): +> `MemFree + Cached` **вместе** падают, а `AnonPages`/`Slab` растут. Тогда память реально +> уходит в процесс и не возвращается. +> +> Здесь: `free + cached` = 09-17 06 → **2 390 МБ**, 09-18 05 → **2 260 МБ** (−130 МБ за сутки, +> и это в пределах колебаний кэша). `MemAvailable` за те же сутки −46 МБ. **Оба почти плоские.** + +### 10a.4. Замер ключевого инварианта (снято 2026-09-18 05:03 UTC, аптайм 23 ч) + +``` +MemTotal: 3 470 776 kB = 3.31 ГБ ✅ память на месте (не 1.44 — регрессии нет) +MemAvailable: 2 508 852 kB = 2.39 ГБ ✅ почти не изменилась за 23 ч +MemFree: 392 588 kB = 383 МБ ← «380 МБ» из вопроса Alex +Cached: 1 925 740 kB = 1.84 ГБ ← вот куда ушла память +SwapTotal/Free: 1 145 356 / 1 145 356 ✅ swap 0 % — ядро НЕ вытесняет, давление низкое +AnonPages: 795 772 kB = 777 МБ ← реально занято приложениями (не растёт) +Slab (SUnreclaim): 39 556 kB = 39 МБ ← ядро не течёт +pressure/memory: some=0.00 full=0.00 ✅ НЕТ давления на память вообще +pressure/io: some=2.55 full=2.20 ← вот это стоит смотреть: I/O-давление +``` + +> 🔴 **Главный вывод: признаков утечки НЕТ.** +> `Swap 0 %` + `pressure/memory = 0.00` = ядру **хватает** памяти, оно ничего не вытесняет +> и не ждёт. Настоящая утечка дала бы рост swap и ненулевой `pressure/memory`. +> +> ⚠️ **Что действительно заслуживает внимания — `pressure/io` (2.2–2.6 %).** +> Это давление на **ввод-вывод**, не на память. Прямо бьётся с главным кандидатом +> расследования — деградацией носителя ([[family/tech/t610-hang-investigation]] §5). +> Но 2 % — **низкое** значение, критичным считается sustained >10–20 %. + +### 10a.5. Что это значит для Alex + +1. **Действий не требуется.** 383 МБ `MemFree` при 2.39 ГБ `MemAvailable` — здоровая картина + Linux; «свободная память» в простое почти всегда низкая, потому что излишки уходят в кэш. +2. **`ram_used` как датчик тренда — плохой выбор** (он растёт от кэша). Смотреть надо + **`ram_available`** (главный) и **`swap_used`** (должен оставаться `0`). +3. **Пропущено в текущем аддоне:** `AnonPages`, `Slab`, `Buffers`, `Active(file)` — их нет + в логе, поэтому «течёт ли реально» приходится выводить косвенно. Добавление `AnonPages` + закрыло бы вопрос утечки **прямым** замером. (`Cached` в логе есть — этого хватило.) +4. **`MemTotal` = 3.31 ГБ держится 23 ч** — регрессии к 1.44 ГБ нет. Это уже полезный факт + для расследования зависаний: ступенька не проявлялась за сутки на 3.31 ГБ. + +--- + ## 11. Связанные - [[family/how-to/home-automation]] — контур автоматизации, §3.5 (ограничения `core_ssh`), §3.9 (память)