# SLUB: 빈 객체 안에 다음 빈 객체를 연결하기

v6.18.37 / mm/slub.c

커널은 수십 바이트의 객체를 만들 때마다 페이지 한 장씩 소비하지 않습니다. SLUB는 페이지를 같은 종류의 객체로 나누고 빈 객체들을 연결해 둡니다. 여기서는 한 객체에서 다음 빈 객체의 위치를 읽는 함수를 통해, 데이터의 주소와 그 주소에 저장된 포인터를 구분합니다.

## get_freepointer

```c

static inline void *get_freepointer(struct kmem_cache *s, void *object)
{
	unsigned long ptr_addr;
	freeptr_t p;

	object = kasan_reset_tag(object);
	ptr_addr = (unsigned long)object + s->offset;
	p = *(freeptr_t *)(ptr_addr);
	return freelist_ptr_decode(s, p, ptr_addr);
}

```

### 585행

```c

static inline void *get_freepointer(struct kmem_cache *s, void *object)

```

캐시 s에 속한 빈 객체 object에서 다음 빈 객체 주소를 읽습니다. static inline은 파일 내부의 짧은 보조 함수임을 나타냅니다.

### 587행

```c

	unsigned long ptr_addr;

```

연결값이 저장된 메모리 위치를 담을 정수 변수를 마련합니다. 아직 다음 객체 주소가 들어 있는 것은 아닙니다.

### 588행

```c

	freeptr_t p;

```

freeptr_t는 메모리에 저장된 연결값의 표현입니다. 디코딩된 void 포인터와 타입부터 구분합니다.

### 590행

```c

	object = kasan_reset_tag(object);

```

KASAN 주소 태그를 정리해 실제 객체 위치 계산에 사용할 주소를 얻습니다. 객체의 내용을 지우는 함수가 아닙니다.

### 591행

```c

	ptr_addr = (unsigned long)object + s->offset;

```

객체 시작에서 캐시가 지정한 offset만큼 이동해 연결값의 저장 위치를 계산합니다.

### 592행

```c

	p = *(freeptr_t *)(ptr_addr);

```

계산한 주소를 freeptr_t 포인터로 해석하고 그 위치의 값을 읽습니다. 주소 계산만 하던 앞줄과 달리 실제 메모리를 읽는 줄입니다.

### 593행

```c

	return freelist_ptr_decode(s, p, ptr_addr);

```

캐시 정보, 저장값, 저장 위치를 이용해 실제 다음 객체 주소를 복원하여 반환합니다. 강화 설정이 없으면 더 단순한 변환이 됩니다.

