> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> ClickHouse의 할당 프로파일링을 자세히 설명하는 페이지

# 할당 프로파일링

ClickHouse는 전역 메모리 할당자로 [jemalloc](https://github.com/jemalloc/jemalloc)을 사용합니다. jemalloc에는 할당 샘플링과 프로파일링을 위한 도구가 포함되어 있습니다.

ClickHouse와 Keeper에서는 구성 파일, 쿼리 설정, `SYSTEM` 명령, 그리고 Keeper의 4문자 명령(4LW)을 사용해 샘플링을 제어할 수 있습니다. 결과를 확인하는 방법은 여러 가지가 있습니다.

* 쿼리별 분석을 위해 `JemallocSample` 유형으로 샘플을 `system.trace_log`에 수집합니다.
* 내장된 [jemalloc 웹 UI](#jemalloc-web-ui)에서 실시간 메모리 통계를 확인하고 힙 프로파일을 가져옵니다(26.2+).
* [`system.jemalloc_profile_text`](#fetching-heap-profiles-from-sql)를 사용해 현재 힙 프로파일을 SQL에서 직접 쿼리합니다(26.2+).
* [`system.jemalloc_sampled_allocations`](#analyzing-fragmentation-from-sql)를 사용해 SQL에서 메모리 단편화를 분석합니다(26.9+).
* 힙 프로파일을 디스크에 플러시한 뒤 [`jeprof`](#analyzing-heap-profile-files-with-jeprof)로 분석합니다.

<Note>
  이 가이드는 25.9+ 버전에 적용됩니다.
  이전 버전은 [25.9 이전 버전용 할당 프로파일링](/ko/concepts/features/performance/allocation-profiling-old)을 확인하십시오.
</Note>

<h2 id="sampling-allocations">
  메모리 할당 샘플링
</h2>

메모리 할당을 샘플링하고 프로파일링하려면 `jemalloc_enable_global_profiler` 설정을 활성화한 상태로 ClickHouse/Keeper를 시작합니다:

```xml theme={null}
<clickhouse>
    <jemalloc_enable_global_profiler>1</jemalloc_enable_global_profiler>
</clickhouse>
```

`jemalloc`은 메모리 할당을 샘플링하고 해당 정보를 내부적으로 저장합니다.

`jemalloc_enable_profiler` 설정을 사용하면 쿼리별 샘플링도 활성화할 수 있습니다.

<Warning>
  **경고**

  ClickHouse는 메모리 할당이 많은 애플리케이션이므로 jemalloc 샘플링 시 성능 오버헤드가 발생할 수 있습니다.
</Warning>

<h2 id="storing-jemalloc-samples-in-system-trace-log">
  `system.trace_log`에 jemalloc 샘플 저장
</h2>

`JemallocSample` 유형으로 jemalloc 샘플을 `system.trace_log`에 저장할 수 있습니다.
전체적으로 활성화하려면 `jemalloc_collect_global_profile_samples_in_trace_log` 설정을 사용하세요:

```xml theme={null}
<clickhouse>
    <jemalloc_collect_global_profile_samples_in_trace_log>1</jemalloc_collect_global_profile_samples_in_trace_log>
</clickhouse>
```

<Warning>
  **경고**

  ClickHouse는 메모리 할당이 많이 발생하는 애플리케이션이므로 system.trace\_log에서 모든 샘플을 수집하면 부하가 크게 증가할 수 있습니다.
</Warning>

`jemalloc_collect_profile_samples_in_trace_log` 설정을 사용하면 쿼리별로도 이를 활성화할 수 있습니다.

<h3 id="example-analyzing-memory-usage-trace-log">
  예시: 쿼리의 메모리 사용량 분석
</h3>

먼저 jemalloc 프로파일러를 활성화한 상태에서 쿼리를 실행하고, 샘플을 `system.trace_log`에 수집합니다:

```sql theme={null}
SELECT *
FROM numbers(1000000)
ORDER BY number DESC
SETTINGS max_bytes_ratio_before_external_sort = 0
FORMAT `Null`
SETTINGS jemalloc_enable_profiler = 1, jemalloc_collect_profile_samples_in_trace_log = 1

Query id: 8678d8fe-62c5-48b8-b0cd-26851c62dd75

Ok.

0 rows in set. Elapsed: 0.009 sec. Processed 1.00 million rows, 8.00 MB (108.58 million rows/s., 868.61 MB/s.)
Peak memory usage: 12.65 MiB.
```

<Note>
  ClickHouse를 `jemalloc_enable_global_profiler`와 함께 시작한 경우 `jemalloc_enable_profiler`를 활성화할 필요가 없습니다.
  `jemalloc_collect_global_profile_samples_in_trace_log`와 `jemalloc_collect_profile_samples_in_trace_log`도 동일합니다.
</Note>

`system.trace_log`를 플러시합니다:

```sql theme={null}
SYSTEM FLUSH LOGS trace_log
```

그런 다음 시간에 따른 누적 메모리 사용량을 확인하기 위해 쿼리합니다:

```sql theme={null}
WITH per_bucket AS
(
    SELECT
        event_time_microseconds AS bucket_time,
        sum(size) AS bucket_sum
    FROM system.trace_log
    WHERE trace_type = 'JemallocSample'
      AND query_id = '8678d8fe-62c5-48b8-b0cd-26851c62dd75'
    GROUP BY bucket_time
)
SELECT
    bucket_time,
    sum(bucket_sum) OVER (
        ORDER BY bucket_time ASC
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS cumulative_size,
    formatReadableSize(cumulative_size) AS cumulative_size_readable
FROM per_bucket
ORDER BY bucket_time
```

메모리 사용량이 가장 높았던 시점을 찾으십시오:

```sql theme={null}
SELECT
    argMax(bucket_time, cumulative_size),
    max(cumulative_size)
FROM
(
    WITH per_bucket AS
    (
        SELECT
            event_time_microseconds AS bucket_time,
            sum(size) AS bucket_sum
        FROM system.trace_log
        WHERE trace_type = 'JemallocSample'
          AND query_id = '8678d8fe-62c5-48b8-b0cd-26851c62dd75'
        GROUP BY bucket_time
    )
    SELECT
        bucket_time,
        sum(bucket_sum) OVER (
            ORDER BY bucket_time ASC
            ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        ) AS cumulative_size,
        formatReadableSize(cumulative_size) AS cumulative_size_readable
    FROM per_bucket
    ORDER BY bucket_time
)
```

해당 결과를 바탕으로 피크 시점에 어떤 할당 스택이 가장 활발했는지 확인합니다:

```sql theme={null}
SELECT
    concat(
        '\n',
        arrayStringConcat(
            arrayMap(
                (x, y) -> concat(x, ': ', y),
                arrayMap(x -> addressToLine(x), allocation_trace),
                arrayMap(x -> demangle(addressToSymbol(x)), allocation_trace)
            ),
            '\n'
        )
    ) AS symbolized_trace,
    sum(s) AS per_trace_sum
FROM
(
    SELECT
        ptr,
        sum(size) AS s,
        argMax(trace, event_time_microseconds) AS allocation_trace
    FROM system.trace_log
    WHERE trace_type = 'JemallocSample'
      AND query_id = '8678d8fe-62c5-48b8-b0cd-26851c62dd75'
      AND event_time_microseconds <= '2025-09-04 11:56:21.737139'
    GROUP BY ptr
    HAVING s > 0
)
GROUP BY ALL
ORDER BY per_trace_sum ASC
```

<h2 id="jemalloc-web-ui">
  Jemalloc 웹 UI
</h2>

<Note>
  이 섹션은 버전 26.2 이상에 적용됩니다.
</Note>

ClickHouse는 `/jemalloc` HTTP 엔드포인트에서 jemalloc 메모리 통계를 확인할 수 있는 내장 웹 UI를 제공합니다.
이 UI는 allocated, active, resident, mapped 메모리를 비롯한 실시간 메모리 메트릭을 차트로 표시하며, arena별 및 빈(bin)별 통계도 제공합니다.
또한 UI에서 전역 및 쿼리별 힙 프로파일을 직접 가져올 수 있습니다.

<Tabs>
  <Tab title="ClickHouse">
    ```text theme={null}
    http://localhost:8123/jemalloc
    ```

    서버 UI에는 Summary, Allocations, Arenas, Operations, Global Profiler, Query Profiler, 단편화, Raw Output 등 모든 탭이 포함되어 있습니다.
  </Tab>

  <Tab title="Keeper">
    ```text theme={null}
    http://localhost:9182/jemalloc
    ```

    Keeper UI는 HTTP control 포트에서 사용할 수 있습니다. 이 포트는 **기본적으로 비활성화되어 있으므로**, Keeper 구성에서 `keeper_server.http_control.port`를 설정해 명시적으로 활성화해야 합니다:

    ```xml theme={null}
    <clickhouse>
        <keeper_server>
            <http_control>
                <port>9182</port>
            </http_control>
        </keeper_server>
    </clickhouse>
    ```

    활성화되면 UI는 system tables에 대한 SQL 액세스가 필요한 Query Profiler 및 단편화 탭을 제외하고, Summary, Allocations, Arenas, Operations, Global Profiler, Raw Output 등 서버와 동일한 시각화를 제공합니다.

    <Warning>
      **보안**

      Keeper HTTP control 포트에는 애플리케이션 수준의 authentication이 없습니다. 모든 데이터 쿼리가 SQL HTTP handler를 통해 처리되고 사용자 이름/비밀번호 자격 증명이 필요한 ClickHouse 서버 jemalloc UI와 달리, Keeper REST API 엔드포인트에는 authentication이 적용되지 않습니다. 이는 다른 Keeper HTTP control 엔드포인트(명령, 스토리지, dashboard)와도 일관됩니다.

      네트워크 수준 제어를 사용해 이 포트에 대한 접근을 제한하십시오. 예를 들어 Keeper를 localhost에 bind하거나, firewall 규칙을 사용하거나, authentication이 적용된 reverse 프록시 뒤에 배치할 수 있습니다. `listen_host`가 구성되지 않은 경우 Keeper는 기본적으로 localhost에서만 수신합니다.
    </Warning>

    Keeper는 프로그래밍 방식으로 접근할 수 있도록 REST API 엔드포인트도 제공합니다:

    * `GET /jemalloc/stats` — 원시 `malloc_stats_print` 출력
    * `GET /jemalloc/status` — JSON 형식의 profiling 상태 (`prof_enabled`, `prof_active`, `thread_active_init`, `lg_sample`)
    * `GET /jemalloc/profile?format={collapsed|raw}` — 힙 프로파일을 플러시하고 서버 측 심볼화를 수행하며, 플레임 그래프 렌더링에 적합한 collapsed stacks(기본값) 또는 원시 jemalloc dump를 반환합니다
  </Tab>
</Tabs>

<h2 id="fetching-heap-profiles-from-sql">
  SQL에서 힙 프로파일 가져오기
</h2>

<Note>
  이 섹션은 버전 26.2 이상에 적용됩니다.
</Note>

`system.jemalloc_profile_text` 시스템 테이블을 사용하면 외부 도구 없이, 먼저 디스크에 플러시하지 않고도 현재 jemalloc 힙 프로파일을 SQL에서 직접 가져와 볼 수 있습니다.

이 테이블에는 단일 컬럼이 있습니다:

| Column | Type | Description |
| - | - | - |
| `line` | String | 심볼화된 jemalloc 힙 프로파일의 한 줄 |

이 테이블은 직접 쿼리할 수 있으므로, 미리 힙 프로파일을 플러시할 필요가 없습니다:

```sql theme={null}
SELECT * FROM system.jemalloc_profile_text
```

<h3 id="output-format">
  출력 형식
</h3>

출력 형식은 `jemalloc_profile_text_output_format` 설정으로 제어되며, 이 설정은 다음 3가지 값을 지원합니다.

* `raw` — jemalloc이 생성한 원시 힙 프로파일입니다.
* `symbolized` — 함수 심볼이 내장된 jeprof 호환 형식입니다. 심볼이 이미 내장되어 있으므로 `jeprof`는 ClickHouse 바이너리 없이도 출력을 분석할 수 있습니다.
* `collapsed` (기본값) — 바이트 수와 함께 한 줄에 하나의 스택이 기록되는 플레임 그래프 호환 collapsed stacks 형식입니다.

예를 들어, 원시 프로필을 가져오려면 다음과 같이 하십시오:

```sql theme={null}
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'raw'
```

심볼이 해석된 결과를 얻으려면:

```sql theme={null}
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'symbolized'
```

<h3 id="fetching-heap-profiles-settings">
  추가 설정
</h3>

* `jemalloc_profile_text_symbolize_with_inline` (Bool, 기본값: `true`) — 심볼화 시 인라인 프레임을 포함할지 여부를 지정합니다. 이 옵션을 비활성화하면 심볼화 속도가 크게 빨라지지만, 인라인된 함수 호출이 스택에 표시되지 않아 정밀도가 떨어집니다. `symbolized` 및 `collapsed` 포맷에만 영향을 줍니다.
* `jemalloc_profile_text_collapsed_use_count` (Bool, 기본값: `false`) — `collapsed` 포맷을 사용할 때 바이트 대신 할당 횟수 기준으로 집계합니다.

<h3 id="example-flamegraph-from-sql">
  예시: SQL로 플레임 그래프 생성
</h3>

기본 출력 형식이 `collapsed`이므로 출력을 FlameGraph로 직접 파이프할 수 있습니다:

```sh theme={null}
clickhouse-client -q "SELECT * FROM system.jemalloc_profile_text" | flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg
```

바이트가 아니라 할당 횟수를 기준으로 flame graph를 생성하려면:

```sh theme={null}
clickhouse-client -q "SELECT * FROM system.jemalloc_profile_text SETTINGS jemalloc_profile_text_collapsed_use_count = 1" | flamegraph.pl --color=mem --title="Allocation Count Flame Graph" --width 2400 > result.svg
```

<h2 id="analyzing-fragmentation-from-sql">
  SQL로 단편화 분석하기
</h2>

<Note>
  이 섹션은 버전 26.9 이상에 적용됩니다.
</Note>

jemalloc은 작은 할당을 슬랩(slab)에서 처리합니다. 슬랩은 하나의 크기 클래스에 해당하는 영역들로 분할된 고정 크기 메모리 블록입니다. 슬랩은 그 안의 모든 영역이 비어 있을 때에만 해제됩니다. 특정 크기 클래스의 할당 대부분이 빠르게 해제되더라도 그중 일부가 오래 살아남으면, 슬랩은 대부분의 영역이 비어 있는 채로 계속 고정되어 남습니다. 메모리는 상주 상태로 남아 있지만 실제로 할당되어 쓰이지는 않습니다. 여기서 말하는 단편화란 바로 이런 상황입니다.

그 원인을 찾는 데는 다음 두 시스템 테이블이 유용합니다:

* [`system.jemalloc_arena_bins`](/ko/reference/system-tables/jemalloc_bins)는 각 아레나에서 크기 클래스별로 얼마나 많은 메모리가 낭비되는지 보여줍니다. `waste`는 슬랩이 점유하고 있지만 활성 할당에는 사용되지 않는 바이트 수입니다. `purpose`는 전용 아레나(`mergetree`, `jit`, `cache`)를 나타내며, 이들은 설계상 수명이 긴 데이터를 보유하므로 예기치 않은 단편화를 찾을 때는 `purpose = ''`로 걸러내십시오. `system.jemalloc_bins`는 동일한 데이터를 아레나 전체에 대해 합산한 값을 제공합니다.
* `system.jemalloc_sampled_allocations`는 현재 살아 있는 샘플링된 할당을 샘플당 한 행씩 나열합니다. 백트레이스(`trace`), 살아 있는 시간(`age_ns`), 크기와 크기 클래스, 그리고 아레나를 확인할 수 있습니다. 이 테이블을 읽으면 새로운 힙 프로파일이 플러시됩니다.

두 테이블을 아레나와 크기 클래스로 조인하면, 낭비가 심한 크기 클래스에서 오래된 객체를 할당한 코드가 무엇인지 알 수 있습니다.

결과를 해석할 때는 다음 사항에 유의하십시오:

* 프로파일러가 활성화된 스레드만 샘플을 생성합니다(구성의 `jemalloc_enable_global_profiler` 또는 `jemalloc_enable_profiler` 설정).
* 각 행은 약 `weight`개의 실제 할당을 대표하며, 작은 할당일수록 샘플링 빈도가 낮습니다. 관심 있는 크기 클래스에 샘플이 없다면 `jemalloc_profiler_sampling_rate`를 조정하십시오.
* 샘플링된 할당은 슬랩에 저장되지 않으므로 그 자체가 `waste`를 늘리지는 않습니다. 해당 크기 클래스에서 어떤 코드가 할당을 수행하는지 알려줄 뿐입니다.
* 살아 있는 샘플 하나마다 할당이 해제될 때까지 페이지 2개(64 KiB 페이지 빌드에서는 128 KiB)가 추가로 소모됩니다. 프로파일러를 비활성화하면 새 샘플 생성은 멈추지만 기존 샘플이 해제되지는 않습니다.

다음 쿼리는 낭비가 1 MiB를 초과하는 크기 클래스에서 생성된 지 1분이 넘은 할당의 백트레이스를 나열합니다:

```sql theme={null}
WITH 60e9 AS min_age_ns
SELECT
    b.arena,
    b.size AS reg_size,
    b.waste AS class_waste,
    s.est_old_objects,
    s.stack
FROM system.jemalloc_arena_bins AS b
INNER JOIN
(
    SELECT
        arena,
        size_class,
        sum(weight) AS est_old_objects,
        arrayStringConcat(arrayMap(a -> demangle(addressToSymbol(a)), arrayReverse(trace)), ';') AS stack
    FROM system.jemalloc_sampled_allocations
    WHERE age_ns > min_age_ns
    GROUP BY arena, size_class, trace
) AS s ON s.size_class = b.index AND s.arena = b.arena
WHERE b.large = 0 AND b.purpose = '' AND b.waste > 1048576
ORDER BY b.waste DESC, s.est_old_objects DESC
SETTINGS allow_introspection_functions=1
```

<h3 id="example-fragmentation-flamegraph">
  예시: 단편화 플레임 그래프 생성
</h3>

동일한 쿼리로 각 크기 클래스의 낭비량을 오래된 할당 수에 비례하여 백트레이스별로 나누고, 그 결과를 `flamegraph.pl`용 `collapsed` 포맷으로 출력할 수 있습니다. 낭비는 있지만 충분히 오래된 샘플이 없는 크기 클래스는 `[unattributed]` 프레임에 포함되므로, 플레임 그래프의 총합은 전체 낭비량과 같습니다. `system.jemalloc_sampled_allocations`는 쿼리당 한 번만 읽으십시오. 읽을 때마다 새로운 profile이 플러시되므로 서브쿼리를 두 개 사용하면 서로 다른 데이터를 보게 됩니다.

```sql theme={null}
WITH 60e9 AS min_age_ns
SELECT format('{} {}',
    if(s.est_old_objects > 0, s.stack, format('[unattributed];arena_{}_class_{}', toString(b.arena), toString(b.size))),
    toString(toUInt64(if(s.est_old_objects > 0, b.waste * s.est_old_objects / sum(s.est_old_objects) OVER (PARTITION BY b.arena, b.index), b.waste))))
FROM system.jemalloc_arena_bins AS b
LEFT JOIN
(
    SELECT
        arena,
        size_class,
        sum(weight) AS est_old_objects,
        arrayStringConcat(arrayMap(a -> demangle(addressToSymbol(a)), arrayReverse(trace)), ';') AS stack
    FROM system.jemalloc_sampled_allocations
    WHERE age_ns > min_age_ns
    GROUP BY arena, size_class, trace
) AS s ON s.size_class = b.index AND s.arena = b.arena
WHERE b.large = 0 AND b.purpose = '' AND b.waste > 0
SETTINGS allow_introspection_functions=1
```

```sh theme={null}
clickhouse-client -q "..." | flamegraph.pl --color=mem --title="Fragmentation Flame Graph" --width 2400 > result.svg
```

<h2 id="flushing-heap-profiles">
  힙 프로파일을 디스크에 플러시하기
</h2>

`jeprof`로 오프라인 분석을 하기 위해 힙 프로파일을 파일로 저장해야 하는 경우, 이를 디스크에 플러시할 수 있습니다.

기본적으로 힙 프로파일 파일은 `/tmp/jemalloc_clickhouse._pid_._seqnum_.heap`에 생성됩니다. 여기서 `_pid_`는 ClickHouse의 PID이고 `_seqnum_`은 현재 힙 프로파일의 전역 시퀀스 번호입니다.
Keeper의 경우 기본 파일은 `/tmp/jemalloc_keeper._pid_._seqnum_.heap`이며, 동일한 규칙을 따릅니다.

현재 프로파일을 플러시하려면 다음을 실행하십시오.

<Tabs>
  <Tab title="ClickHouse">
    ```sql theme={null}
    SYSTEM JEMALLOC FLUSH PROFILE
    ```

    플러시된 프로파일의 위치가 반환됩니다.
  </Tab>

  <Tab title="Keeper">
    ```sh theme={null}
    echo jmfp | nc localhost 9181
    ```
  </Tab>
</Tabs>

`MALLOC_CONF` 환경 변수에 `prof_prefix` 옵션을 추가해 다른 위치를 지정할 수 있습니다.
예를 들어, 파일 이름 접두사를 `my_current_profile`로 하여 `/data` 폴더에 프로파일을 생성하려면 다음 환경 변수와 함께 ClickHouse/Keeper를 실행하면 됩니다.

```sh theme={null}
MALLOC_CONF=prof_prefix:/data/my_current_profile
```

생성된 파일 이름에는 prefix, PID, 시퀀스 번호가 덧붙습니다.

<h2 id="analyzing-heap-profile-files-with-jeprof">
  `jeprof`를 사용한 힙 프로파일 파일 분석
</h2>

힙 프로파일을 디스크에 플러시한 후에는 [jeprof](https://github.com/jemalloc/jemalloc/blob/dev/bin/jeprof.in)라는 `jemalloc` 도구를 사용해 분석할 수 있습니다. `jeprof`는 여러 가지 방법으로 설치할 수 있습니다:

* 시스템 패키지 관리자를 사용합니다
* [jemalloc 저장소](https://github.com/jemalloc/jemalloc)를 클론한 다음 루트 디렉터리에서 `autogen.sh`를 실행합니다. 그러면 `bin` 폴더에 있는 `jeprof` 스크립트를 사용할 수 있습니다

사용할 수 있는 출력 형식은 다양합니다. 전체 옵션 목록은 `jeprof --help`를 실행해 확인하십시오.

<h3 id="symbolized-heap-profiles">
  심볼화된 힙 프로파일
</h3>

버전 26.1+부터 ClickHouse는 `SYSTEM JEMALLOC FLUSH PROFILE`로 플러시할 때 심볼화된 힙 프로파일을 자동으로 생성합니다.
심볼화된 프로파일(`.symbolized` 확장자)에는 함수 심볼이 내장되어 있으므로 ClickHouse 바이너리 없이도 `jeprof`로 분석할 수 있습니다.

예를 들어, 다음을 실행하면:

```sql theme={null}
SYSTEM JEMALLOC FLUSH PROFILE
```

ClickHouse는 심볼화된 프로파일의 경로(예: `/tmp/jemalloc_clickhouse.12345.0.heap.symbolized`)를 반환합니다.

그런 다음 `jeprof`를 사용해 이를 직접 분석할 수 있습니다:

```sh theme={null}
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --output_format [ > output_file]
```

<Note>
  **바이너리가 필요하지 않습니다**: 심볼화된 프로파일(`.symbolized` 파일)을 사용하는 경우 `jeprof`에 ClickHouse 바이너리 경로를 지정할 필요가 없습니다. 따라서 다른 머신에서 프로파일을 분석하거나 바이너리가 업데이트된 후에 분석할 때도 훨씬 수월합니다.
</Note>

이전의 심볼화되지 않은 힙 프로파일이 있고 ClickHouse 바이너리에 계속 접근할 수 있다면, 기존 방식을 사용할 수 있습니다:

```sh theme={null}
jeprof path/to/clickhouse path/to/heap/profile --output_format [ > output_file]
```

<Note>
  심볼 정보가 없는 프로필의 경우 `jeprof`는 스택트레이스를 생성하기 위해 `addr2line`을 사용하므로 매우 느릴 수 있습니다.
  이런 경우에는 이 도구의 [대체 구현](https://github.com/gimli-rs/addr2line)을 설치하는 것이 좋습니다.

  ```bash theme={null}
  git clone https://github.com/gimli-rs/addr2line.git --depth=1 --branch=0.23.0
  cd addr2line
  cargo build --features bin --release
  cp ./target/release/addr2line path/to/current/addr2line
  ```

  또는 `llvm-addr2line`도 동일하게 잘 작동합니다(단, `llvm-objdump`는 `jeprof`와 호환되지 않으므로 유의하십시오)

  이후에는 다음과 같이 사용할 수 있습니다. `jeprof --tools addr2line:/usr/bin/llvm-addr2line,nm:/usr/bin/llvm-nm,objdump:/usr/bin/objdump,c++filt:/usr/bin/llvm-cxxfilt`
</Note>

두 프로필을 비교할 때는 `--base` 인수를 사용할 수 있습니다:

```sh theme={null}
jeprof --base /path/to/first.heap.symbolized /path/to/second.heap.symbolized --output_format [ > output_file]
```

<h3 id="examples">
  예시
</h3>

심볼이 포함된 프로파일 사용(권장):

* 각 프로시저를 줄별로 기록한 텍스트 파일을 생성합니다:

```sh theme={null}
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --text > result.txt
```

* 콜 그래프가 포함된 PDF 파일을 생성합니다:

```sh theme={null}
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --pdf > result.pdf
```

심볼화되지 않은 프로파일 사용(바이너리 필요):

* 각 프로시저를 한 줄에 하나씩 적은 텍스트 파일을 생성합니다:

```sh theme={null}
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --text > result.txt
```

* 호출 그래프가 포함된 PDF 파일을 생성합니다:

```sh theme={null}
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --pdf > result.pdf
```

<h3 id="generating-flame-graph">
  플레임 그래프 생성하기
</h3>

`jeprof`를 사용하면 플레임 그래프를 생성하는 데 필요한 collapsed stacks를 만들 수 있습니다.

`--collapsed` 인수를 사용해야 합니다:

```sh theme={null}
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --collapsed > result.collapsed
```

또는 심볼화되지 않은 프로파일 사용 시:

```sh theme={null}
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --collapsed > result.collapsed
```

그다음에는 collapsed stacks를 시각화하는 데 여러 도구를 사용할 수 있습니다.

가장 널리 쓰이는 도구는 [FlameGraph](https://github.com/brendangregg/FlameGraph)로, `flamegraph.pl`이라는 스크립트가 포함되어 있습니다:

```sh theme={null}
cat result.collapsed | /path/to/FlameGraph/flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg
```

또 다른 흥미로운 도구로 [speedscope](https://www.speedscope.app/)가 있으며, 이를 사용하면 수집된 스택을 더 인터랙티브하게 분석할 수 있습니다.

<h2 id="additional-options-for-profiler">
  프로파일러 추가 옵션
</h2>

`jemalloc`에는 프로파일러와 관련된 다양한 옵션이 있으며, `MALLOC_CONF` 환경 변수를 수정해 제어할 수 있습니다.
예를 들어, 할당 샘플 간 인터벌은 `lg_prof_sample`로 제어할 수 있습니다.
N바이트마다 힙 프로파일을 dump하려면 `lg_prof_interval`을 활성화하면 됩니다.

전체 옵션 목록은 `jemalloc`의 [참고 페이지](https://jemalloc.net/jemalloc.3.html)에서 확인하는 것이 좋습니다.

<h2 id="other-resources">
  기타 리소스
</h2>

ClickHouse/Keeper는 `jemalloc` 관련 메트릭을 여러 방식으로 노출합니다.

<Warning>
  **경고**

  이 메트릭들은 서로 동기화되지 않으므로 값이 서로 어긋날 수 있다는 점에 유의해야 합니다.
</Warning>

<h3 id="system-table-asynchronous_metrics">
  시스템 테이블 `asynchronous_metrics`
</h3>

```sql theme={null}
SELECT *
FROM system.asynchronous_metrics
WHERE metric LIKE '%jemalloc%'
FORMAT Vertical
```

[참고](/ko/reference/system-tables/asynchronous_metrics)

<h3 id="system-table-jemalloc_bins">
  시스템 테이블 `jemalloc_bins`
</h3>

모든 arena에서 집계한 jemalloc 메모리 할당자의 각 크기 클래스(bin)별 메모리 할당 정보를 포함합니다.

[참고](/ko/reference/system-tables/jemalloc_bins)

<h3 id="system-table-jemalloc_stats">
  시스템 테이블 `jemalloc_stats` (26.2+)
</h3>

`malloc_stats_print()`의 전체 출력 결과를 하나의 문자열로 반환합니다. `SYSTEM JEMALLOC STATS` 명령과 동일합니다.

```sql theme={null}
SELECT * FROM system.jemalloc_stats
```

<h3 id="prometheus">
  Prometheus
</h3>

`asynchronous_metrics`의 모든 `jemalloc` 관련 메트릭은 ClickHouse와 Keeper 모두에서 Prometheus 엔드포인트를 통해서도 제공됩니다.

[참고](/ko/reference/settings/server-settings/settings/other#prometheus)

<h3 id="jmst-4lw-command-in-keeper">
  Keeper의 `jmst` 4LW 명령
</h3>

Keeper는 [기본 메모리 할당자 통계](https://github.com/jemalloc/jemalloc/wiki/Use-Case%3A-Basic-Allocator-Statistics)를 반환하는 `jmst` 4LW 명령을 지원합니다:

```sh theme={null}
echo jmst | nc localhost 9181
```
