๏ปฟ# Shrinker (์ฌ๋๋ธ/์บ์ ํ์ ํ๋ ์์ํฌ)
๊ด๋ จ ์์ค:mm/shrinker.c,include/linux/shrinker.h,include/linux/list_lru.h
๊ฐ์ (Overview)
Shrinker๋ ๋ฆฌ๋
์ค ์ปค๋์ ๋ฉ๋ชจ๋ฆฌ ํ์ ํ๋ ์์ํฌ์์ slab ์บ์, dentry ์บ์, inode ์บ์ ๋ฑ ๋ค์ํ ์บ์ ์ค๋ธ์ ํธ๋ฅผ ์์ถ(reclaim)ํ๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ์ํฉ์์ kswapd๋ direct reclaim ๊ฒฝ๋ก๋ฅผ ํตํด ํธ์ถ๋๋ฉฐ, ๊ฐ ์บ์๋ count_objects์ scan_objects ์ฝ๋ฐฑ์ ๋ฑ๋กํ์ฌ ์์ฒด์ ์ธ ํ์ ๋ก์ง์ ๊ตฌํํฉ๋๋ค.
Linux 7.0์์๋ memcg(memory cgroup) ์ธ์ shrinker์ NUMA ์ธ์ shrinker๋ฅผ ์ง์ํ๋ฉฐ, RCU ๊ธฐ๋ฐ์ lockless ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋์์ฑ ์ฑ๋ฅ์ ๋ณด์ฅํฉ๋๋ค. list_lru ํ๋ ์์ํฌ์ ํตํฉ๋์ด dentry/inode ์บ์ ํ์์ ํ์ฉ๋๋ฉฐ, shrink_slab()์ด ์ต์ข
์ง์
์ ์ผ๋ก ๋์ํฉ๋๋ค.
๋์๊ด์ผ๋ก ๋น์ ํ๋ฉด shrinker๋ ๋ฐ๋ฉ๋ ๋ค์ชฝ์์ ์ฐธ๊ณ ์์ ์นด๋๋ชฉ๋ก์ ์ ๋ฆฌํ๋ ์ง์์ ๊ฐ๊น์ต๋๋ค. ์๊ฐ์ ๋ค์ ๊ฝ์๋๋ฉด ๋๋ ์ฑ ์ฒ๋ผ ํ์ผ ๊ธฐ๋ฐ ํ์ด์ง๋ ๋์คํฌ์์ ๋ค์ ์ฝ์ ์ ์๊ณ , ๊ฐ์ธ ๋ ธํธ์ฒ๋ผ ์ต๋ช ํ์ด์ง๋ swap์ด ์์ด์ผ ๋ค์ ์ด๋ฆด ์ ์์ต๋๋ค.
๋ฉ๋ชจ๋ฆฌ ์๋ฐ์ ๋ณดํต kswapd๊ฐ WMARK_HIGH/WMARK_LOW/WMARK_MIN ๊ฐ์ zone ์ํฐ๋งํฌ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฐฑ๊ทธ๋ผ์ด๋ ์ ๋ฆฌ๋ฅผ ์์ํ๊ฑฐ๋, ํ ๋น ๊ฒฝ๋ก๊ฐ ์ง์ reclaim์ผ๋ก ๋ค์ด๊ฐ๋ฉด์ ๋์ ๋๋๋ค. ์ด๋ shrink_node()๊ฐ LRU๋ฅผ ๋จผ์ ์ ๋ฆฌํ๊ณ , ๊ทธ ๋ค์ shrink_slab()์ด dentry/inode/slab ๊ฐ์ ์บ์๋ฅผ ๋น์ฐ๋ ์์ผ๋ก ์ด์ด์ง๋๋ค. MGLRU๊ฐ ์ผ์ง ๊ฒฝ์ฐ์๋ ์ด ์บ์ ํ์ ๋จ๊ณ ์์ฒด๋ ๊ฐ์ ์์น์ ๋จ์ต๋๋ค.
์์ค ํ์ผ ๊ฒฝ๋ก:
mm/shrinker.c โ ํต์ฌ ๊ตฌํ
include/linux/shrinker.h โ struct shrinker, shrink_control ์ ์
include/linux/list_lru.h โ list_lru์ shrinker ํตํฉ
include/linux/memcontrol.h โ memcg๋ณ shrinker_info ์ ์
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# ๋ฑ๋ก๋ shrinker ๋ชฉ๋ก ํ์ธ
ls /sys/kernel/debug/shrinker/
# ํน์ shrinker์ ํ์ ํต๊ณ ํ์ธ
cat /sys/kernel/debug/shrinker/<name>/nr_deferred
# slab ์บ์ ํํฉ (SLUB)
cat /proc/slabinfo | head -20
# memcg๋ณ slab ์ฌ์ฉ๋
cat /sys/fs/cgroup/memory/<cgroup>/slabinfo
# ๋ฉ๋ชจ๋ฆฌ ํ์ ๊ด๋ จ vmstat
grep -E 'slabs_scanned|slabs_freed' /proc/vmstat
# slabtop์ผ๋ก ์ค์๊ฐ ๋ชจ๋ํฐ๋ง
slabtop -o -s c
# ํน์ ์บ์์ shrinker ๋์ ์ถ์
echo 1 > /sys/kernel/debug/tracing/events/vmscan/mm_shrink_slab_start/enable
cat /sys/kernel/debug/tracing/trace_pipe
# shrinker ๋ฑ๋ก ํด์ ์ RCU ๋๊ธฐ ํ์ธ
cat /proc/meminfo | grep -E 'Slab|SReclaimable|SUnreclaim'
# ๋ฉ๋ชจ๋ฆฌ ์๋ฐ ์งํ ํ์ธ
cat /proc/pressure/memory
# kswapd / direct reclaim ํต๊ณ ํ์ธ
grep -E 'pgscan_kswapd|pgsteal_kswapd|pgscan_direct|pgsteal_direct|allocstall' /proc/vmstat
# zone ์ํฐ๋งํฌ ํ์ธ
cat /proc/zoneinfo | grep -E 'Node|pages free|min|low|high'
# ํ์ ์ถ์ธ๋ฅผ 1์ด ๊ฐ๊ฒฉ์ผ๋ก ๋ณด๊ธฐ
vmstat 1 10
# ์ฌ๋ฉ ์บ์์์ dentry / inode ์ํ๋ฅผ ๋น ๋ฅด๊ฒ ๋ณด๊ธฐ
grep -E 'dentry|inode' /proc/slabinfo | head -10
# ํ์ผ ์บ์ ํ์ ์๋ ฅ ํ์ธ
cat /proc/sys/vm/vfs_cache_pressure
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
struct shrinker (`include/linux/shrinker.h:82-118`)
struct shrinker {
unsigned long (*count_objects)(struct shrinker *,
struct shrink_control *sc);
unsigned long (*scan_objects)(struct shrinker *,
struct shrink_control *sc);
long batch;
int seeks;
unsigned flags;
refcount_t refcount;
struct completion done;
struct rcu_head rcu;
void *private_data;
struct list_head list;
#ifdef CONFIG_MEMCG
int id;
#endif
#ifdef CONFIG_SHRINKER_DEBUG
int debugfs_id;
const char *name;
struct dentry *debugfs_entry;
#endif
atomic_long_t *nr_deferred;
};
๋ฐํ๊ฐ ์ ์ (`include/linux/shrinker.h:58-59`)
#define SHRINK_STOP (~0UL)
#define SHRINK_EMPTY (~0UL - 1)
struct shrink_control (`include/linux/shrinker.h:34-56`)
struct shrink_control {
gfp_t gfp_mask; /* ํ์ฌ ํ ๋น ์ปจํ
์คํธ */
int nid; /* NUMA ๋
ธ๋ ID */
unsigned long nr_to_scan; /* ์ค์บํ ์ค๋ธ์ ํธ ์ */
unsigned long nr_scanned; /* ์ค์ ์ค์บ๋ ์ค๋ธ์ ํธ ์ */
struct mem_cgroup *memcg; /* ๋์ memcg */
};
struct shrinker_info_unit (`include/linux/shrinker.h:16-19`)
/* memcg๋ณ shrinker ๋นํธ๋งต ๋จ์ โ 64๊ฐ shrinker๋ฅผ ํ๋์ unit์ผ๋ก ๊ด๋ฆฌ */
struct shrinker_info_unit {
atomic_long_t nr_deferred[SHRINKER_UNIT_BITS]; /* shrinker๋ณ ๋ฏธ์ฐ๊ธฐ ์์
์ */
DECLARE_BITMAP(map, SHRINKER_UNIT_BITS); /* ํ์ ๋์ shrinker ๋นํธ๋งต */
};
struct shrinker_info (`include/linux/shrinker.h:21-25`)
/* memcg์ ๋
ธ๋๋ณ shrinker ๊ด๋ฆฌ ์ ๋ณด */
struct shrinker_info {
struct rcu_head rcu;
int map_nr_max; /* ๋ฑ๋ก๋ shrinker ์ต๋ ์ */
struct shrinker_info_unit *unit[]; /* ์ ์ฐํ ๋ฐฐ์ด (flexible array) */
};
ํ๋๊ทธ ์ ์ (`include/linux/shrinker.h:121-132`)
#define SHRINKER_REGISTERED BIT(0) /* shrinker_list์ ๋ฑ๋ก๋จ */
#define SHRINKER_ALLOCATED BIT(1) /* shrinker_alloc()์ผ๋ก ํ ๋น๋จ */
#define SHRINKER_NUMA_AWARE BIT(2) /* NUMA๋ณ ๊ฐ๋ณ ํ์ */
#define SHRINKER_MEMCG_AWARE BIT(3) /* memcg๋ณ ๊ฐ๋ณ ํ์ */
#define SHRINKER_NONSLAB BIT(4) /* slab์ด ์๋ non-slab shrinker */
ํต์ฌ ํจ์
1. `do_shrink_slab()` โ ํต์ฌ ํ์ ์์ง (`mm/shrinker.c:371-466`)
static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
struct shrinker *shrinker, int priority)
{
unsigned long freed = 0;
unsigned long long delta;
long total_scan;
long freeable;
long nr;
long new_nr;
long batch_size = shrinker->batch ? shrinker->batch
: SHRINK_BATCH;
long scanned = 0, next_deferred;
freeable = shrinker->count_objects(shrinker, shrinkctl);
if (freeable == 0 || freeable == SHRINK_EMPTY)
return freeable;
nr = xchg_nr_deferred(shrinker, shrinkctl);
if (shrinker->seeks) {
delta = freeable >> priority;
delta *= 4;
do_div(delta, shrinker->seeks);
} else {
delta = freeable / 2;
}
total_scan = nr >> priority;
total_scan += delta;
total_scan = min(total_scan, (2 * freeable));
trace_mm_shrink_slab_start(shrinker, shrinkctl, nr,
freeable, delta, total_scan, priority);
while (total_scan >= batch_size ||
total_scan >= freeable) {
unsigned long ret;
unsigned long nr_to_scan = min(batch_size, total_scan);
shrinkctl->nr_to_scan = nr_to_scan;
shrinkctl->nr_scanned = nr_to_scan;
ret = shrinker->scan_objects(shrinker, shrinkctl);
if (ret == SHRINK_STOP)
break;
freed += ret;
count_vm_events(SLABS_SCANNED, shrinkctl->nr_scanned);
total_scan -= shrinkctl->nr_scanned;
scanned += shrinkctl->nr_scanned;
cond_resched();
}
next_deferred = max_t(long, (nr + delta - scanned), 0);
next_deferred = min(next_deferred, (2 * freeable));
new_nr = add_nr_deferred(next_deferred, shrinker, shrinkctl);
trace_mm_shrink_slab_end(shrinker, shrinkctl->nid, freed, nr, new_nr, total_scan);
return freed;
}
๋ถ๊ธฐ ๋ก์ง:
count_objects()๊ฐ SHRINK_EMPTY ๋ฐํ โ ์ฆ์ ์ข
๋ฃ (์ค๋ธ์ ํธ ์์)seeks > 0 โ freeable >> priority * 4 / seeks ๊ณ์ฐ (IO ์บ์ ๋ณดํธ)seeks == 0 โ freeable / 2 (IO ๋ถํ์ ์บ์๋ ๊ณต๊ฒฉ์ ํ์)scan_objects()๊ฐ SHRINK_STOP ๋ฐํ โ ํ์ฌ ํ์ ์ปจํ
์คํธ ์ค๋จtotal_scan < batch_size && total_scan < freeable โ while ๋ฃจํ ํ์ถ2. `shrink_slab()` โ ์ต์ข ์ง์ ์ (`mm/shrinker.c:614-676`)
unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg,
int priority)
{
unsigned long ret, freed = 0;
struct shrinker *shrinker;
/* memcg ๋น-root์ด๋ฉด memcg ์ ์ฉ ๊ฒฝ๋ก๋ก ๋ถ๊ธฐํ๋ค. */
if (!mem_cgroup_disabled() && !mem_cgroup_is_root(memcg))
return shrink_slab_memcg(gfp_mask, nid, memcg, priority);
/* ๊ธ๋ก๋ฒ shrink๋ RCU ๋ณดํธ ์๋ shrinker_list๋ฅผ ์ํํ๋ค. */
rcu_read_lock();
list_for_each_entry_rcu(shrinker, &shrinker_list, list) {
struct shrink_control sc = {
.gfp_mask = gfp_mask,
.nid = nid,
.memcg = memcg,
};
if (!shrinker_try_get(shrinker))
continue;
rcu_read_unlock();
ret = do_shrink_slab(&sc, shrinker, priority);
if (ret == SHRINK_EMPTY)
ret = 0;
freed += ret;
rcu_read_lock();
shrinker_put(shrinker);
}
rcu_read_unlock();
cond_resched();
return freed;
}
3. `shrink_slab_memcg()` โ memcg ์ ์ฉ ํ์ (`mm/shrinker.c:469-585`)
memcg๋ณ ๋นํธ๋งต(shrinker_info)์ ์ํํ๋ฉฐ do_shrink_slab()์ ํธ์ถํฉ๋๋ค. SHRINK_EMPTY ๋ฐ์ ์ ์ด์ค ๊ฒ์ฌ(double-check) ๋ก์ง์ผ๋ก ๊ฒฝํฉ์ ๋ฐฉ์งํฉ๋๋ค.
4. `shrinker_alloc()` โ shrinker ๋์ ํ ๋น (`mm/shrinker.c:678-736`)
SHRINKER_MEMCG_AWARE ํ๋๊ทธ ์ shrinker_memcg_alloc()์ผ๋ก IDR ํ ๋น, ๋ฏธ์์ ์ fallback์ผ๋ก non-memcg ๊ฒฝ๋ก ์ํ.
5. `shrinker_register()` โ shrinker ๋ฑ๋ก (`mm/shrinker.c:738-759`)
shrinker_list์ ์ถ๊ฐํ๊ณ debugfs ๋ฑ๋ก, ์ด๊ธฐ refcount=1 ์ค์ .
6. `shrinker_free()` โ shrinker ํด์ (`mm/shrinker.c:769-811`)
์ด๊ธฐ refcount ํด์ โ completion ๋๊ธฐ โ list ์ ๊ฑฐ โ RCU ์ฝ๋ฐฑ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ํด์ .
ํธ์ถ ํ๋ฆ
๋ฉ๋ชจ๋ฆฌ ์๋ฐ ๋ฐ์
โ
โโ kswapd() โ balance_pgdat() [mm/vmscan.c:6950-7056]
โ โโ shrink_node() [mm/vmscan.c:6039-6105]
โ โโ lru_gen_shrink_node() [MGLRU ์ผ์ง]
โ โโ shrink_lruvec() [mm/vmscan.c:5772-5788]
โ โโ shrink_slab()
โ
โโ direct reclaim โ try_to_free_pages() [mm/vmscan.c:6566-6606]
โโ do_try_to_free_pages()
โโ shrink_node()
โโ shrink_lruvec()
โโ shrink_slab()
๋ฉ๋ชจ๋ฆฌ ์๋ฐ์ด ๋ค์ด์ค๋ฉด ๋จผ์ LRU ํ์ด์ง ํ์๊ฐ ์์๋๊ณ , ํ์ผ ๊ธฐ๋ฐ ํ์ด์ง์ ์ต๋ช
ํ์ด์ง์ ๋น์ค์ ์กฐ์ ํ ๋ค, ์ฌ๋๋ธ ๊ณ์ด ์บ์๋ ๊ทธ ๋ค์ ๋จ๊ณ์์ ์ค์ด๋ญ๋๋ค. shrink_slab()์ ์ด ์ ์ฒด ํ์ ํ๋ฆ์ ๋ง์ง๋ง ์บ์ ์ ๋ฆฌ ๋จ๊ณ์
๋๋ค.
shrink_lruvec()๋ get_scan_count()๋ก anon/file ๋น์ค์ ๋๋๊ณ , inactive list๋ถํฐ active list๋ก ์๋ ฅ์ ์ฎ๊ธฐ๋ฉด์ ํ์๋์ ๋ง์ถฅ๋๋ค.
๋ฉ๋ชจ๋ฆฌ ํ์ ํธ๋ฆฌ๊ฑฐ (kswapd / direct reclaim / drop_slab)
โ
โโ shrink_slab(gfp_mask, nid, memcg, priority) [mm/shrinker.c:614]
โ โ
โ โโ [memcg ๋น-root] โ shrink_slab_memcg() [mm/shrinker.c:469]
โ โ โ
โ โ โโ rcu_read_lock() + shrinker_info ํ๋
โ โ โโ for_each_set_bit(offset, unit->map)
โ โ โ โ
โ โ โ โโ idr_find(&shrinker_idr, shrinker_id)
โ โ โ โโ shrinker_try_get(shrinker)
โ โ โ โโ do_shrink_slab() [mm/shrinker.c:371]
โ โ โ โ
โ โ โ โโ count_objects() โ ์ฌ์ฉ์ ์ฝ๋ฐฑ
โ โ โ โโ xchg_nr_deferred()
โ โ โ โโ total_scan ๊ณ์ฐ (priority ๊ธฐ๋ฐ)
โ โ โ โโ while (total_scan >= batch_size)
โ โ โ โ โโ scan_objects() โ ์ฌ์ฉ์ ์ฝ๋ฐฑ
โ โ โ โโ add_nr_deferred() (์ด์)
โ โ โ
โ โ โโ [SHRINK_EMPTY ์ ์ด์ค ๊ฒ์ฌ]
โ โ โโ clear_bit() + smp_mb__after_atomic()
โ โ โโ do_shrink_slab() ์ฌํธ์ถ
โ โ โโ ๋น์ด์์ผ๋ฉด ๊ทธ๋๋ก, ์๋๋ฉด set_shrinker_bit()
โ โ
โ โโ [root memcg] โ ๊ธ๋ก๋ฒ shrink ๊ฒฝ๋ก
โ โโ rcu_read_lock()
โ โโ list_for_each_entry_rcu(shrinker_list)
โ โ โโ shrinker_try_get()
โ โ โโ do_shrink_slab()
โ โ โโ shrinker_put()
โ โโ rcu_read_unlock()
โ
โโ ๋ฐํ: ํ์๋ ์ค๋ธ์ ํธ ์
shrinker ๋ฑ๋ก/ํด์ ํ๋ฆ:
shrinker_alloc(flags, fmt, ...) [mm/shrinker.c:678]
โโ [SHRINKER_MEMCG_AWARE] โ shrinker_memcg_alloc()
โ โโ idr_alloc() + expand_shrinker_info()
โโ [non-memcg] โ nr_deferred ๋ฐฐ์ด ํ ๋น
shrinker_register(shrinker) [mm/shrinker.c:738]
โโ list_add_tail_rcu(shrinker_list)
โโ SHRINKER_REGISTERED ํ๋๊ทธ ์ค์
โโ shrinker_debugfs_add()
โโ refcount_set(1)
shrinker_free(shrinker) [mm/shrinker.c:769]
โโ shrinker_put() โ refcount--
โโ wait_for_completion(done)
โโ list_del_rcu() + shrinker_debugfs_detach()
โโ call_rcu() โ shrinker_free_rcu_cb() โ kfree()
์กฐ๊ฑด๋ณ ๋น๊ต
๋ฉ๋ชจ๋ฆฌ ์๋ฐ ์ง์ ์ ๋น๊ต
| ์ง์ ์ | ์์ ์กฐ๊ฑด | ์ฃผ๋ ํ๋ฆ | ํน์ง |
|---|---|---|---|
| kswapd | ์ํฐ๋งํฌ ๋๋ฌ, ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ ํ์ | `balance_pgdat()` โ `shrink_node()` โ `shrink_slab()` | ๋ค๋ฅธ ์์ ์ ๋ง์ง ์๋๋ก ๋น๋๊ธฐ์ ์ผ๋ก ์์ง์ |
| direct reclaim | ํ ๋น ๊ฒฝ๋ก์์ ์ฆ์ ํ์ ํ์ | `try_to_free_pages()` โ `shrink_node()` โ `shrink_slab()` | ํ์ฌ ํธ์ถ์ ์ค๋ ๋๊ฐ ์ง์ ๊ธฐ๋ค๋ฆผ |
| drop_caches | ๊ด๋ฆฌ์๊ฐ ์๋ ํด์ | `drop_slab()` ๊ณ์ด๋ก ์บ์ ์ ๋ฆฌ | ํ์ผ์์คํ ์บ์๋ฅผ ๊ฐ์ ๋ก ์ค์ผ ๋ ์ฌ์ฉ |
ํ์ ๋์๋ณ ์ฐจ์ด
| ๋์ | ๋จผ์ ์ค์ด๋๋๊ฐ | ๋ค์ ์ฑ์ฐ๋ ๋ฐฉ๋ฒ | shrinker์์ ๊ด๊ณ |
|---|---|---|---|
| ํ์ผ ๊ธฐ๋ฐ ํ์ด์ง | ๊ทธ๋ ๋ค | ํ์ผ์์ ๋ค์ ์ฝ์ | LRU ํ์์ ์ฃผ์ ๋์ |
| ์ต๋ช ํ์ด์ง | ์๋๋ค | swap์์ ๋ค์ ๊ฐ์ ธ์ด | swap์ด ์์ด์ผ ํ์ ๊ฐ๋ฅ |
| dentry / inode / slab ์บ์ | ์ํฉ์ ๋ฐ๋ผ ๋ค๋ฆ | ํ์ ์ ์ฌ์์ฑ | `count_objects()` / `scan_objects()`๋ก ํ์ |
Shrinker ํ๋๊ทธ๋ณ ๋์
| ํ๋๊ทธ | ๋์ | ์ฌ์ฉ ์์ |
|---|---|---|
| `SHRINKER_NUMA_AWARE` | NUMA ๋ ธ๋๋ณ `nr_deferred` ๋ถ๋ฆฌ | ํ์ผ ์์คํ inode ์บ์ ๋ฑ |
| `SHRINKER_MEMCG_AWARE` | memcg๋ณ `shrinker_info` ๋นํธ๋งต ๊ด๋ฆฌ | ์ปจํ ์ด๋ ํ๊ฒฝ slab ์บ์ |
| `SHRINKER_NONSLAB` | memcg offlines์์๋ ํ์ ํ์ฉ | non-slab ์บ์ (DAMON ๋ฑ) |
| `SHRINKER_REGISTERED` | `shrinker_list`์ ๋ฑ๋ก๋จ | ๋ด๋ถ ํ๋๊ทธ |
| `SHRINKER_ALLOCATED` | `shrinker_alloc()`์ผ๋ก ํ ๋น๋จ | ๋ด๋ถ ํ๋๊ทธ |
ํ์ ๊ฒฝ๋ก ๋น๊ต
| ๊ฒฝ๋ก | ์ง์ ์กฐ๊ฑด | ์ํ ๋์ | ๋์์ฑ ์ ์ด |
|---|---|---|---|
| ๊ธ๋ก๋ฒ shrink | root memcg | `shrinker_list` ์ ์ฒด | RCU + refcount |
| memcg shrink | ๋น-root memcg | memcg๋ณ `shrinker_info` ๋นํธ๋งต | RCU + ๋นํธ๋งต |
| drop_slab | `/proc/sys/vm/drop_caches` | ๋ชจ๋ memcg ์ํ | ๋ณ๋ lock ๋ถํ์ |
count_objects ๋ฐํ๊ฐ ์ฒ๋ฆฌ
| ๋ฐํ๊ฐ | ์๋ฏธ | ํ์ ๋์ |
|---|---|---|
| `0` | ํ์ ๋ถ๊ฐ (์ ์ ์์) | ์ค์บ ์คํต |
| `SHRINK_EMPTY` | ์ค๋ธ์ ํธ 0๊ฐ (ํ์ค) | ์ฆ์ ์ข ๋ฃ, memcg ์ ๋นํธ๋งต ํด๋ฆฌ์ด |
| ์์ | ํ์ ๊ฐ๋ฅ ์ค๋ธ์ ํธ ์ | total_scan ๊ณ์ฐ ํ scan_objects ํธ์ถ |