Ghostty의 가장 큰 메모리 누수를 찾아 수정하기

4 weeks ago 11

  • Ghostty 터미널 에뮬레이터에서 장기간 실행 시 수십 GB의 메모리를 점유하는 심각한 누수 현상이 발견됨
  • 문제의 원인은 PageList 구조체의 비표준 메모리 페이지 재사용 로직에서 munmap이 호출되지 않아 해제되지 않은 메모리가 누적된 것
  • Claude Code CLI가 다중 코드포인트 그래프 출력을 자주 생성하면서, 비표준 페이지 사용 빈도가 높아져 누수가 대규모로 드러남
  • 수정은 비표준 페이지를 재사용하지 않고 즉시 해제하도록 변경되었으며, macOS의 VM 태그 기능을 활용해 누수 추적 및 검증이 이루어짐
  • 이 수정은 Ghostty의 가장 큰 누수 문제 해결로 평가되며, 향후 릴리스(1.3)에 포함될 예정

Ghostty의 메모리 누수 개요

  • 일부 사용자가 Ghostty가 장시간 실행 후 37GB 이상의 메모리를 사용하는 사례를 보고
    • 누수는 최소 버전 1.0부터 존재했으며, 최근 CLI 앱들이 특정 조건을 충족해 문제를 노출
  • 수정 사항은 이미 GitHub에 병합되었고, nightly 빌드 및 1.3 정식 릴리스에 포함 예정

PageList 구조와 메모리 관리 방식

  • Ghostty는 터미널 내용을 저장하기 위해 PageList라는 이중 연결 리스트 구조를 사용
    • 각 페이지는 문자, 스타일, 하이퍼링크 등의 데이터를 포함
  • 페이지는 mmap으로 할당되며, 표준 크기 페이지 풀(pool) 을 통해 재사용
    • 표준 크기 이하 페이지는 풀로 반환
    • 비표준 크기 페이지는 직접 munmap으로 해제해야 함
  • 이 구조 자체는 정상적이지만, 최적화 로직의 버그로 인해 누수가 발생

Scrollback 최적화와 버그 발생 원인

  • Ghostty는 scrollback-limit을 초과하면 가장 오래된 페이지를 재사용하는 최적화를 수행
    • 새 페이지 할당 없이 포인터만 조정해 성능 향상
  • 문제는 이 과정에서 비표준 페이지의 메타데이터만 표준 크기로 변경하고 실제 메모리는 그대로 둔 점
    • 이후 해제 시 표준 페이지로 오인되어 munmap이 호출되지 않음
  • 이로 인해 비표준 페이지가 해제되지 않고 누적, 장기 실행 시 대규모 메모리 누수 발생

Claude Code와 누수의 대규모 노출

  • Claude Code CLI가 다중 코드포인트 그래프 출력을 자주 생성해 비표준 페이지 사용 빈도 증가
    • 또한 스크롤백 출력이 많아 누수가 빠르게 누적
  • Ghostty의 설계상 비표준 페이지는 드물게 발생해야 하지만, Claude Code의 특성으로 인해 누수가 대량으로 재현
  • 개발자는 이 버그가 Claude Code의 문제가 아니라 Ghostty 내부 로직의 결함임을 명시

수정 내용

  • 해결책은 비표준 페이지를 재사용하지 않고 즉시 해제(munmap) 하는 방식
    • 스크롤백 중 비표준 페이지 발견 시 새 표준 페이지를 풀에서 재할당
  • 일부 사용자는 비표준 페이지 재사용 전략을 제안했으나, 현재는 단순하고 안전한 수정이 우선 적용
  • 수정 코드 예시: if (first.data.memory.len > std_size) { self.destroyNode(first); break :prune; }

VM 태그를 활용한 누수 추적

  • macOS의 Mach 커널 VM 태그 기능을 사용해 PageList 메모리 할당에 특정 태그를 부여
    • 디버깅 시 Ghostty의 메모리 영역을 명확히 식별 가능
    • 누수 원인 추적 및 수정 검증에 큰 도움을 줌
  • 이 기능으로 PageList 관련 메모리 해제 여부를 시각적으로 확인 가능

Ghostty의 메모리 누수 방지 체계

  • Ghostty는 다양한 방식으로 누수를 탐지 및 방지
    • 디버그 빌드와 단위 테스트에서 Zig의 누수 감지 할당자 사용
    • CI에서 valgrind로 전체 테스트 수행
    • macOS Instruments로 Swift 코드 누수 검사
    • GTK 관련 PR은 Valgrind GUI 테스트로 검증
  • 이번 누수는 특정 조건에서만 발생해 기존 테스트로는 재현되지 않았음
    • 새 테스트 케이스가 추가되어 회귀 방지 확보

결론

  • 이번 문제는 Ghostty에서 가장 큰 규모의 메모리 누수로 확인된 사례
  • 수정 후에도 사용자 보고와 재현 테스트를 통해 지속적인 모니터링 예정
  • 커뮤니티의 진단 데이터와 재현 사례 제공이 문제 해결에 결정적 역할
  • 재현 가능한 환경 확보가 메모리 누수 해결의 핵심임을 강조

Read Entire Article