1P by GN⁺ | ★ favorite | 댓글 1개
  • Jane Street의 OCaml 상위 집합인 OxCaml[@zero_alloc]으로 함수 호출 트리 전체의 힙 할당 금지를 컴파일러에 선언할 수 있게 함
  • 선언된 호출 경로에서 할당이 생기면 컴파일 실패로 바로 드러나며, 프로파일러로 나중에 찾는 방식보다 회귀를 빠르게 막을 수 있음
  • C, C++, Java, Go, C#, Rust, Zig, OCaml 등에서는 보통 핫 패스의 할당을 프로파일러로 찾아 줄이는 접근이 중심임
  • 핫 패스 코드는 작은 수정만으로도 다시 할당을 만들 수 있어, 기존 최적화 맥락을 잊으면 같은 조사를 반복하게 됨
  • Zig나 최신 Rust 일부의 allocator 전달 관례도 도움이 되지만, 관례보다 컴파일러 검사가 더 직접적인 안전장치가 됨

[@zero_alloc]이 바꾸는 할당 관리

  • OxCaml은 Jane Street의 OCaml 상위 집합이며, 함수가 힙에 할당하지 않는다는 단언을 지원함
  • 함수에 [@zero_alloc]을 붙이면 해당 함수뿐 아니라 그 아래 호출 트리까지 힙 할당 여부를 컴파일러가 확인함
  • 호출 트리 안에서 할당이 발생하면 빌드가 실패하고, 컴파일러가 할당 발생을 알려줌
  • 정적 분석으로 비슷한 검사를 만들 가능성은 있지만, 생성된 요약 기준으로는 이런 기능을 컴파일러 자체에 넣은 주류 언어는 드묾

프로파일러 중심 접근과의 차이

  • 다른 언어들에서는 보통 프로파일러로 할당을 찾아낸 뒤, 특히 수백만 번 실행되는 루프 안의 할당을 제거하거나 줄임
  • C, C++, Java, Go, C#, Rust, Zig, OCaml 등이 프로파일러 중심 접근의 예로 나열됨
  • 핫 패스의 한 줄만 바꿔도 다시 할당이 들어갈 수 있고, 그 원인을 찾기 위해 프로파일러로 되돌아가야 함
  • Zig나 최신 Rust 일부에서는 allocator를 함수에 전달하지 않는 방식으로 회귀를 줄일 수 있지만, 이는 관례에 의존함
  • [@zero_alloc]의 차이는 사후 분석이나 팀 규칙이 아니라, 빌드 시점에 컴파일러가 할당 회귀를 차단한다는 데 있음

댓글과 토론

Lobste.rs 의견들
  • Zig에서 allocator를 함수 인자로 넘기는 이유가, 인자로 allocator를 받지 않는 함수는 힙 할당을 할 수 없게 하려는 것이라고 이해했는데 맞는지 궁금함
    “규약은 무시될 수 있다”는 말이 정말 맞다면 의도와 다른 것 같음

    • 맞음, 결국 규약일 뿐임
      함수 안에서도 밖에서 하듯이 allocator를 새로 만들어낼 수 있음
  • gift link: https://theconsensus.dev/p/2026/…

  • Rust에서 core만 사용하는 것도 할당을 피하는 한 방법임

    • “할당 피하기”는 이야기의 일부일 뿐임
      그 접근은 결국 “의존성을 통제하라”거나 “전체 호출 그래프를 수동으로 확인하라”에 가까움
      글의 초점은 컴파일러 같은 도구가 어떤 속성을 정적으로 강제하고, 그 속성이 깨지는 지점을 생산적으로 찾아내는 작업 흐름을 제공하는 방식에 있음
  • D에는 @nogc가 있고, 그다음은 명확한 할당 패턴을 가진 직접 통제 가능한 추상화만 쓰는 문제임

  • 기사 제목을 설명적으로 짓는 능력을 잃어버린 탓에 덧붙이면, 핵심은 함수에 [@zero_alloc]을 붙이고 그 함수의 호출 트리가 힙을 건드리면 컴파일러가 프로그램을 거부하게 하는 기능임

  • 이런 방식이 “예외를 던지거나 패닉하지 않음”, “잠금 없음”, “항상 종료함” 같은 여러 조건에도 적용될 수 있을지 궁금함