# Jik: 가비지 컬렉터 없이 메모리 오류 막기
# Jik: catching memory errors without a garbage collector

- Site: https://select1.dev/2026-11-03 (English), https://select1.dev/ko/2026-11-03 (Korean)
- Entry: 024
- Published: 2026-11-03 (KST). Launch date: 2026-11-02
- Pick: Jik <https://github.com/jik-lang/jik> (source: Show HN)
- Verified: ran
- What: Jik 은 가비지 컬렉터 없이 프로그램의 메모리를 관리하는 프로덕트다. C 로 컴파일되는 프로그래밍 언어다. 문자열, 구조체 같은 값은 영역에 할당되고, 영역을 해제하면 그 안의 값도 함께 해제된다.
- What (en): Jik is a product that manages a program’s memory without a garbage collector. It is a programming language that compiles to C. Values such as strings and structs go into regions, and freeing a region frees the values in it.
- Why: 오늘의 픽으로 선정한 이유는 가비지 컬렉터 없이도 컴파일러가 메모리 오류를 잡기 때문이다.
- Why (en): It is today’s pick because its compiler catches memory errors without a garbage collector.
- Verdict: 작동한다. 다른 영역의 값을 잘못 참조하는 코드를 컴파일러가 거부했다.
- Verdict (en): It works. The compiler rejected code that referred to a value in the wrong region.
- Tags: programming-language, memory, compiler, c, regions

## Checked against the README

- [pass] 컴파일러가 수명이 다른 영역 사이의 참조를 막는다(compiler checks prevent references across regions with incompatible lifetimes) — 함수의 지역 문자열을 다른 영역의 구조체 필드에 저장하는 호출을 넣자 region mismatch 오류로 컴파일이 실패했다. 문자열 리터럴을 인자로 직접 넘기자 컴파일에 성공했다
- [pass] 함수는 자신의 지역 영역에 할당한 복합 값을 반환할 수 없다(a function cannot safely return a composite value allocated in its own local region) — 지역 영역에 만든 구조체를 반환하는 함수를 넣자 cannot return local allocation 오류로 컴파일이 실패했다
- [pass] 셀프 호스팅 컴파일러의 2단계와 3단계는 같은 C 코드를 생성해야 한다(Stages 2 and 3 must generate identical C) — make test-bootstrap-full 이 57초 만에 끝났다. 생성한 C 에 런타임 코드를 포함한 경우와 제외한 경우 모두 C comparison passed: stages 2 and 3 match 가 출력됐다

## Measured

- 정수 2,000,000개를 문자열로 바꾸는 반복문을 실행했을 때 main 의 영역 크기, 최대 메모리 사용량, 실행 시간. main 안에서 반복한 경우와 반복마다 함수를 호출한 경우. 4코어 가상 머신, clang: 반복문 안에서 바로 변환한 경우: main 의 영역 96 MB, 최대 메모리 사용량 97.8 MB, 실행 시간 0.14초. 변환을 함수로 옮겨 반복마다 호출한 경우: main 의 영역 66 KB, 최대 메모리 사용량 11.1 MB, 실행 시간 0.25초 (jik build 로 만든 실행 파일을 Python 의 subprocess 로 실행해 ru_maxrss 를 읽었다. 영역 크기는 region::total_bytes 로 출력했다)

## 한국어

## 무엇이 문제인가

C 처럼 메모리를 직접 할당하고 해제하는 언어에서는 해제한 메모리를 다시 사용하거나 해제를 빠뜨리는 실수가 생긴다. 가비지 컬렉터가 있는 언어는 이 실수를 막는 대신, 사용하지 않는 메모리를 실행 중에 찾아 해제하는 비용이 든다.

제작자는 README 에서 Jik 이 가비지 컬렉션도, 수동 힙 할당도 사용하지 않는다고 밝혔다. Go 공식 문서의 가비지 컬렉터 안내서에 따르면, Go 는 모든 프로그램에 런타임 라이브러리를 함께 넣는다. 그 안의 가비지 컬렉터가 더는 필요 없는 메모리를 찾아 회수한다. 같은 문서에 따르면 가비지 컬렉터는 물리 메모리와 CPU 시간을 쓴다. 메모리를 더 쓰게 하면 CPU 시간이 줄고, 메모리를 아끼면 CPU 시간이 는다.

## 어떻게 해결했나

Jik 은 2026년 11월 2일 Hacker News 에 Show HN 글로 올라왔다. Jik 코드는 C 로 번역된 뒤 clang 이나 gcc 로 컴파일된다. 문자열, 벡터, 구조체 같은 복합 값은 영역에 할당된다. 모든 함수에는 지역 영역이 있다. 함수가 끝나면 그 영역과 영역 안의 값이 함께 해제된다.

함수가 문자열이나 구조체 같은 값을 반환하려면 호출자가 영역을 인자로 넘겨야 한다. 함수는 그 영역에 값을 할당한다. 컴파일러는 함수를 호출할 때 인자로 넘기는 값들이 같은 영역에 있는지 검사한다. 더 오래 남는 값이 그보다 먼저 해제되는 영역의 값을 가리키지 못하게 하기 위해서다. 제작자는 Jik 컴파일러도 Jik 으로 작성했다. 저장소에는 C 로 작성한 초기 컴파일러가 있고, 이 초기 컴파일러로 Jik 컴파일러를 빌드한다.

## 무엇이 다른가

첫째, 메모리를 회수하는 시점이 다르다. Jik 은 함수가 끝날 때 그 함수의 영역을 한꺼번에 해제하므로, Go 와 달리 실행 중에 회수할 메모리를 찾는 작업이 없다. 트레이드오프는 함수가 끝나기 전에는 영역의 메모리가 해제되지 않는다는 점이다. 긴 반복문 안에서 할당한 값은 다음 반복으로 넘어가도 함수가 끝날 때까지 남는다.

둘째, 메모리 안전성을 검사하는 방법이 다르다. C 컴파일러는 해제한 메모리를 가리키는 코드도 컴파일한다. Jik 컴파일러는 함수가 지역 영역에 할당한 값을 반환하거나, 구조체에 다른 영역의 값을 저장하면 컴파일하지 않는다. 트레이드오프는 프로그래머가 결과를 담을 영역을 함수의 인자로 넘기고, 함수를 호출할 때 인자로 넘기는 값들을 같은 영역에 두어야 한다는 점이다. 값을 읽기만 하는 함수는 컴파일러가 안전하다고 판단해 이 규칙에서 제외한다.

## 어떻게 만들었나

- 커밋 207개는 2026년 4월 25일부터 11월 2일까지 개발자 한 명이 작성했다. Co-authored-by 트레일러는 없다.
- 상태는 베타(v0.1.0-beta.1)다. 제작자는 알려진 한계를 docs/known-issues.md 에 정리했다.
- 테스트는 C 로 된 초기 컴파일러용과 Jik 컴파일러용이 따로 있다.

## 실행해 보니

clang 으로 저장소를 빌드하고, 4코어 가상 머신에서 README 의 명령을 따라 실행했다.

1. 빌드. `make` 는 16초 만에 끝났다. 컴파일러 실행 파일은 927 KB 였다. 생성된 C 코드를 컴파일하는 동안 C 컴파일러가 경고 238개를 출력했다.
2. 테스트. `make test` 를 실행하자 검사 13,036개가 14초 만에 모두 통과했다.
3. 영역 검사. 지역 영역에 만든 구조체를 반환하는 함수를 넣자 컴파일 오류가 났다. 함수의 지역 문자열을 다른 영역의 구조체에 저장하는 호출도 거부됐다. 문자열 리터럴을 인자로 직접 넘기자 컴파일에 성공했다. 문서에 따르면 이때 컴파일러가 리터럴을 구조체의 영역에 할당한다.
4. 반복문의 메모리. 정수 2,000,000개를 문자열로 바꾸는 반복을 main 안에 두자 main 의 영역이 96 MB 까지 커졌다. 최대 메모리 사용량은 97.8 MB 였다. 같은 작업을 함수로 옮겨 반복마다 호출하자 main 의 영역은 66 KB, 최대 메모리 사용량은 11.1 MB 였다. 실행 시간을 한 번씩 측정하니 main 안에서 반복한 쪽이 0.14초, 함수를 호출한 쪽이 0.25초였다. 저장소의 메모리 관리 문서와 알려진 한계 문서에는 반복문 안의 할당에 대한 안내가 없다.
5. 셀프 호스팅. `make test-bootstrap-full` 은 초기 컴파일러에서 시작해, 앞 단계에서 만든 컴파일러로 다음 단계의 Jik 컴파일러를 세 번 이어서 빌드한다. 57초 만에 끝났다. 2단계 컴파일러와 3단계 컴파일러가 생성한 C 코드가 같았다. 컴파일러가 자신을 다시 빌드해도 결과가 달라지지 않는다는 뜻이다.

```
jik error: cannot return local allocation
      --> bad_return.jik:7:12
jik error: region mismatch
      --> bad_store.jik:11:15
    = all storing/returning call arguments must belong to the same region
```

## 확인하지 못한 것

- C 라이브러리 호출. 패키지 저장소 jik-packages 에는 C 게임 라이브러리 Raylib 의 바인딩이 있다. 이 바인딩으로 예제 게임을 빌드해 보자.
- Windows. 제작자는 Windows x64 에서도 테스트했다고 밝혔다. gcc 로 빌드하고 `make test` 를 실행해 보자.

## 판정

작동한다. 다른 영역의 값을 잘못 참조하는 코드를 컴파일러가 거부했다. 다만 반복문 안에서 할당한 값은 함수가 끝날 때까지 남아, 반복할수록 메모리 사용량이 커진다. 가비지 컬렉터 없이 C 보다 안전한 언어가 필요한 경우에 써 볼 만하다.

### 용어

- 영역: 여러 값을 함께 할당해 두는 메모리 공간이다. 값을 하나씩 해제하지 않고 영역 전체를 한꺼번에 해제한다.
- 셀프 호스팅: 컴파일러를 그 컴파일러가 컴파일하는 언어로 작성해, 컴파일러가 자신을 직접 빌드하게 하는 방식이다.
- 바인딩: 다른 언어로 작성한 함수를 호출할 수 있도록, 호출하는 언어에서 그 함수의 이름과 타입을 선언한 것이다.

## English

## The problem

In languages like C, you allocate and free memory yourself. This leads to mistakes such as using memory after freeing it or forgetting to free it. Languages with a garbage collector prevent these mistakes, but at run time the collector spends time finding and freeing unused memory.

In the README, the maker says Jik avoids both garbage collection and manual heap allocation. The official Go guide to the garbage collector says every Go program ships with a runtime library. Its garbage collector finds memory that is no longer needed and recycles it. The same guide says the garbage collector uses physical memory and CPU time. Using less of one means using more of the other.

## How it solves it

Jik was posted on Hacker News as a Show HN on November 2, 2026. Jik code is translated to C, then compiled with clang or gcc. Composite values such as strings, vectors and structs are allocated in regions. Every function has a local region, and when the function returns, the region and its values are freed together.

The caller passes a region as an argument. The function allocates its return value in that region. The compiler checks that the values passed in one call are in the same region. This keeps a longer-lived value from pointing at a value in a region that is freed earlier. The compiler itself is written in Jik. The repository includes a seed compiler written in C that builds it.

## What is different

The first difference is when memory is reclaimed. Jik frees a function’s whole region when the function returns. Unlike in Go, nothing searches for memory to reclaim at run time. The tradeoff is that a region’s memory is not freed before its function returns. Values allocated inside a long loop are not freed when the loop ends.

The second difference is how memory safety is checked. A C compiler accepts code that points at freed memory. Jik’s compiler rejects a function that returns a value from its local region. It also rejects a call that stores a local value in a struct from another region. The tradeoff is that the programmer passes a region argument for each result. The values passed in one call must share one region. The compiler proves that functions which only read values are safe, so they are exempt from this rule.

## How it was built

- The repository has 207 commits from April 25 to November 2, 2026, all by one person. No commit has a Co-authored-by trailer.
- Jik is in beta (v0.1.0-beta.1), and its known limitations are listed in docs/known-issues.md.
- There are separate tests for the seed compiler in C and for the Jik compiler.

## Running it

I built the repository with clang and followed the README’s commands on a 4-core virtual machine.

1. Build. `make` finished in 16 seconds, and the compiler binary was 927 KB. The C compiler printed 238 warnings on the generated C.
2. Tests. `make test` passed all 13,036 checks in 14 seconds.
3. Region checks. The compiler rejected a function that returned a struct from its local region. It also rejected a call that stored a function’s local string in a struct from another region. Passing a string literal directly worked. According to the documentation, the compiler allocates such a literal in the struct’s region.
4. Memory in loops. A loop in main that turned 2,000,000 integers into strings grew main’s region to 96 MB. Peak memory use was 97.8 MB. When I moved the work into a function called on each iteration, main’s region stayed at 66 KB and peak memory use was 11.1 MB. Measured once each, the loop in main took 0.14 seconds and the version with function calls took 0.25 seconds. The repository’s memory management page and known issues page say nothing about allocating in loops.
5. Self-hosting. `make test-bootstrap-full` starts from the seed compiler and builds the Jik compiler three times in a row. Each build uses the compiler from the previous build. It finished in 57 seconds, and the second and third builds generated the same C code. Rebuilding the compiler with itself no longer changes its output.

```
jik error: cannot return local allocation
      --> bad_return.jik:7:12
jik error: region mismatch
      --> bad_store.jik:11:15
    = all storing/returning call arguments must belong to the same region
```

## Not checked

- Calling C libraries. Build the example game with the Raylib binding in jik-packages, the Jik package repository. Raylib is a game library written in C.
- Windows. According to the maker, Windows x64 is also a tested platform. Build with gcc there and run `make test`.

## Verdict

It works. The compiler rejected code that referred to a value in the wrong region. But values allocated inside a loop stay until the function returns, so memory use grows with each iteration. It is worth trying if you need a safer alternative to C without a garbage collector.

### Terms

- region: A unit of memory that holds values allocated together, so they can all be freed at once instead of one by one.
- self-hosting: Writing a compiler in the language it compiles, so the compiler can build itself.
- binding: A declaration that links a function written in another language to a name and type in this language, so you can call it.

## Launches the same day

- Wikihack <https://wikihack.netlify.app> (Show HN, 326): Hacker News 에서 언급된 Wikipedia 글 모음. 언급이 많은 순서로 정렬해 스크롤 피드로 보여 준다.
- syscall.sh <https://syscall.sh/> (Show HN, 182): Linux 시스템 콜 표 사이트. 27개 아키텍처의 번호와 인자를 커널 소스에서 읽어 보여 주고, JSON API 도 제공한다.
- HackerHack <https://news.ycombinator.com/> (Show HN, 180): 패러디 글. HackerBooks 를 본떠 Hacker News 첫 화면에 연결했다.
- Hacker News but for comments <https://news.ycombinator.com/newcomments> (Show HN, 19): 패러디 글. Hacker News 의 최신 댓글 페이지에 연결했다.
- trustmebro.reviews <https://www.trustmebro.reviews/r/hackernews> (Show HN, 9): 제품 의견 모음 사이트. Reddit 과 HN 에서 제품 4만 8천 개에 대한 의견 1,300만 개를 로컬 모델로 추출했다고 소개한다.
- Jik <https://github.com/jik-lang/jik> (Show HN, 6): 프로그래밍 언어. C 로 컴파일되고, 가비지 컬렉션 대신 영역 단위로 메모리를 관리한다.
- uncut <https://github.com/Balanov/uncut> (GitHub, 570): 코딩 에이전트 하네스. 7 MB 단일 바이너리이고, 대화를 줄이지 않고 매번 모델에 보낸다고 소개한다.
- beacon.sh <https://www.producthunt.com/products/asymptotelabs> (Product Hunt, 338): AI 코딩 에이전트용 기억 저장소. 오픈소스이고 스스로 개선된다고 소개한다.
- Xmind 2027 <https://www.producthunt.com/products/xmind> (Product Hunt, 215): 마인드맵 앱의 새 버전. AI 가 생각을 함께 정리한다고 소개한다.
- UnleashX <https://www.producthunt.com/products/unleashx> (Product Hunt, 193): AI 업무 에이전트. 대화를 결과로 바꾼다고 소개한다.

## Getting started

- Steps: git clone https://github.com/jik-lang/jik && cd jik ; make ; ./jik run examples/hello.jik
- Needs: Make 와 clang 또는 gcc. Jik 으로 작성한 프로그램을 빌드할 때도 C 컴파일러가 필요하다
- Cost: MIT, 무료.
- Note: 제작자에 따르면 Jik 은 베타 단계라 아직 버그가 있을 수 있고 언어 사양도 바뀔 수 있다.
