그레이든 호어의 2006년 실험부터 오늘날의 러스트 생태계까지, 가비지 컬렉터 없이 메모리 안전을 확보한 방식이 시스템 프로그래밍의 기대를 어떻게 바꿨는지 살펴봅니다.

이 글은 집중된 기원 이야기를 전합니다: 어떻게 그레이든 호어의 개인 실험이 러스트로 자라났고, 왜 러스트의 설계 선택이 시스템 프로그래밍에 대한 기대를 바꿨는지 말입니다.
“시스템 프로그래밍”은 기계(하드웨어)와 가깝고 제품의 위험 지점과도 가깝게 위치합니다. 브라우저, 게임 엔진, 운영체제 구성요소, 데이터베이스, 네트워킹, 임베디드 소프트웨어 같은 곳에서 나타나며, 보통 다음을 요구합니다:
역사적으로 이 조합은 팀을 C와 C++로 몰아갔고, 메모리 관련 버그를 줄이기 위한 광범위한 규칙, 리뷰, 도구가 뒤따랐습니다.
러스트의 핵심 약속은 말하기는 쉬우나 실현은 어렵습니다:
가비지 컬렉터 없이 메모리 안전성.
러스트는 use-after-free, double-free, 다양한 종류의 데이터 레이스 같은 일반적인 실패를 방지하는 것을 목표로 하지만, 프로그램을 주기적으로 중단해 메모리를 회수하는 런타임에 의존하지 않습니다. 대신 러스트는 소유권과 빌림을 통해 많은 작업을 컴파일 시점으로 이동시킵니다.
여기서는 초기 아이디어부터 Mozilla 참여까지의 역사와 핵심 개념(소유권, 빌림, 수명, 안전 vs unsafe)을 평이한 언어로 설명합니다.
제공하지 않는 것은 러스트의 전체 튜토리얼, 문법 완전 정복, 단계별 프로젝트 설정입니다. 이 글은 러스트 설계의 ‘왜’에 초점을 맞추며 개념을 구체화할 충분한 예시만 담습니다.
작가 노트: 전체 글은 약 3,000단어를 목표로 하며, 참조서가 되지 않도록 예시는 간결하게 유지합니다.
러스트는 위원회가 설계한 “차세대 C++”로 시작하지 않았습니다. 2006년 그레이든 호어가 개인적으로 시작한 실험에서 출발했고, 이후 더 넓은 관심을 끌었습니다. 이 기원은 중요합니다: 초기 설계 결정들 대부분은 이론을 ‘이기기’ 위해가 아니라 일상적 고통을 해결하기 위한 시도로 읽힙니다.
호어는 가비지 컬렉터에 의존하지 않으면서 저수준 고성능 소프트웨어를 작성하고, 동시에 C와 C++의 충돌과 보안 버그의 가장 흔한 원인을 피하는 방법을 모색했습니다. 시스템 프로그래머에게 이 긴장은 익숙합니다:
러스트의 ‘가비지 없는 메모리 안전’ 방향은 처음엔 마케팅 문구가 아니라 설계 목표였습니다: 시스템 작업에 적합한 성능 특성을 유지하면서 많은 범주의 메모리 버그를 표현하기 어렵게 만들자고 한 것입니다.
‘그냥 C/C++용 더 나은 컴파일러’가 왜 안 되었는지 묻는 건 타당합니다. 정적 분석, sanitizer, 안전한 라이브러리들은 많은 문제를 막지만, 근본 언어가 허용하는 패턴은 외부에서 완전히 보장하기 어렵습니다.
러스트는 핵심 규칙을 언어와 타입 시스템으로 옮겨 안전을 기본 결과로 만들되, 명확히 표시된 탈출구에서 수동 제어를 허용하는 데 베팅했습니다.
러스트 초기의 몇몇 이야기는 회고나 강연에서 반복되며 일화처럼 퍼집니다. 이 기원 이야기를 할 때는 2006년 시작과 Mozilla 채택 같은 잘 문서화된 이정표와 개인 회고·2차 서술을 구분하는 것이 유용합니다.
주요 출처로는 초기 러스트 문서와 설계 노트, 그레이든 호어의 강연/인터뷰, 그리고 프로젝트가 어떻게 채택되고 목표가 어떻게 정해졌는지 설명한 Mozilla/Servo 시절의 포스트들을 찾아보세요. 추가 읽을거리 섹션은 그런 원천들을 가리킬 수 있습니다(관련 링크는 /blog 참조).
시스템 프로그래밍은 하드웨어에 가깝게 작업하는 경우가 많습니다. 이 근접성 덕분에 코드는 빠르고 자원을 효율적으로 쓰지만, 메모리 실수는 매우 치명적입니다.
몇 가지 고전적 버그가 반복해서 등장합니다:
이런 오류는 항상 명백하지 않습니다. 프로그램이 수 주간 동작하다가 드문 타이밍이나 입력 패턴에서만 충돌할 수 있습니다.
테스트는 당신이 시도한 경우에 대해서만 작동을 증명합니다. 메모리 버그는 흔히 테스트하지 않은 경우에 숨어 있습니다: 비정상 입력, 다른 하드웨어, 미세한 타이밍 변화, 또는 컴파일러 버전의 변화 등. 멀티스레드 환경에서는 비결정적일 수 있어서, 로깅을 추가하거나 디버거를 붙이면 버그가 사라지기도 합니다.
메모리가 잘못되면 단순한 오류를 넘어 상태 손상, 예측 불가능한 충돌, 공격자가 적극적으로 찾는 보안 취약점이 생깁니다. 팀들은 재현하기 어렵고 진단하기 더 어려운 실패를 추적하느라 큰 노력을 소비합니다.
저수준 소프트웨어는 무거운 런타임 검사나 지속적인 메모리 스캔의 비용을 항상 ‘지불’할 수는 없습니다. 목표는 공유 작업장에서 도구를 빌리는 것과 유사합니다: 자유롭게 쓰되 규칙이 명확해야 한다—누가 그것을 소유하는지, 누가 공유할 수 있는지, 언제 반납해야 하는지. 전통적 시스템 언어는 그 규칙을 인간의 규율에 맡겼습니다. 러스트의 기원 이야기는 그 트레이드오프에 의문을 제기하는 데서 시작합니다.
가비지 컬렉션(GC)은 언어가 메모리 버그를 예방하는 일반적인 방식입니다. 런타임이 어떤 객체가 여전히 도달 가능한지 추적하고 그렇지 않은 것을 자동으로 회수하면 use-after-free, double-free, 많은 누수 문제를 제거할 수 있습니다.
GC가 ‘나쁘다’는 건 아닙니다만, 프로그램의 성능 프로파일을 바꿉니다. 대부분의 수집기는 다음 중 일부를 도입합니다:
웹 백엔드나 비즈니스 소프트웨어 같은 많은 애플리케이션에서는 이런 비용이 허용 가능하거나 눈에 띄지 않습니다. 현대 GC는 훌륭하고 개발 생산성을 극적으로 높여줍니다.
시스템 프로그래밍에서는 최악의 경우(worst case)가 종종 가장 중요합니다. 브라우저 엔진은 매끄러운 렌더링이 필요하고, 임베디드 컨트롤러는 엄격한 타이밍 제약이 있을 수 있으며, 저지연 서버는 부하 하에서 꼬리 지연(tail latency)을 좁게 유지하도록 조정될 수 있습니다. 이런 환경에서 ‘보통 빠름’은 ‘일관되게 예측 가능함’만큼 가치가 없을 수 있습니다.
러스트의 큰 약속은: C/C++ 수준의 메모리 및 데이터 레이아웃 제어는 유지하되, 가비지 컬렉터에 의존하지 않고 메모리 안전을 제공하겠다는 것입니다. 목표는 예측 가능한 성능 특성—동시에 안전한 코드를 기본값으로 만드는 것입니다.
이것은 GC가 열등하다는 주장이 아닙니다. 대신 중요한 중간지대가 있다는 데 베팅한 것입니다: 저수준 제어와 현대적인 안전 보장이 동시에 필요한 소프트웨어입니다.
소유권은 러스트의 가장 단순하지만 큰 아이디어입니다: 각 값은 하나의 소유자를 가지며, 그 소유자가 더 이상 필요하지 않을 때 정리 책임을 진다.
이 한 규칙은 C와 C++ 개발자들이 머릿속으로 추적하던 많은 ‘누가 이걸 해제하나?’ 수작업 bookkeeping을 대체합니다. 규율에 의존하는 대신 러스트는 정리를 예측 가능하게 만듭니다.
무언가를 복사하면 두 개의 독립된 버전을 얻게 됩니다. 이동하면 원본을 넘겨주는 것입니다—이동 후에는 옛 변수로 그 값을 사용할 수 없습니다.
러스트는 문자열, 버퍼, 벡터 같은 힙 할당 값들을 기본적으로 이동으로 취급합니다. 무분별한 복사는 비용이 많이 들 수 있고, 더 중요한 것은 혼란을 초래할 수 있습니다: 두 변수가 같은 할당을 ‘소유’한다고 생각하면 메모리 버그의 무대가 마련됩니다.
다음은 아주 간단한 의사 코드입니다:
buffer = make_buffer()
ownerA = buffer // ownerA owns it
ownerB = ownerA // move ownership to ownerB
use(ownerA) // not allowed: ownerA no longer owns anything
use(ownerB) // ok
// when ownerB ends, buffer is cleaned up automatically
항상 정확히 하나의 소유자가 있기 때문에 러스트는 값이 언제 정리되어야 하는지를 정확히 압니다: 소유자가 스코프를 벗어날 때. 즉 자동 메모리 관리(여기저기 free()를 호출할 필요 없음)를 제공하면서도 주기적으로 프로그램을 멈춰 메모리를 회수하는 가비지 컬렉터가 필요 없습니다.
이 소유권 규칙은 전형적인 문제의 많은 부분을 막습니다:
러스트의 소유권 모델은 안전한 습관을 권장하는 것에 그치지 않고, 많은 불안전 상태를 표현 불가능하게 만들어 다른 안전 기능들의 기초가 됩니다.
소유권이 누가 값을 ‘소유’하는지 설명한다면, 빌림은 프로그램의 다른 부분이 그 값을 일시적으로 어떻게 사용할 수 있는지를 설명합니다.
러스트에서 빌리면 참조를 얻습니다. 원래의 소유자는 메모리 정리에 책임을 지고, 빌린 쪽은 그 값을 잠시 사용할 수 있는 권한만 가집니다.
러스트에는 두 종류의 빌림이 있습니다:
\u0026T): 읽기 전용 접근.\n- 가변 빌림(\u0026mut T): 읽기-쓰기 접근.러스트의 중앙 빌림 규칙은 말하기는 간단하지만 실무에서 강력합니다:
이 규칙은 프로그램의 한 부분이 데이터를 읽는 동안 다른 부분이 그걸 바꾸는 흔한 버그를 막습니다.
참조는 그것이 가리키는 것이 사라진 뒤에도 남아 있지 않아야 안전합니다. 러스트는 이 기간을 수명(lifetime) 이라고 부릅니다—참조가 유효하다고 보장되는 시간 범위입니다.
형식적 이론 없이도 이 아이디어를 쓸 수 있습니다: 참조는 그 소유자가 사라진 뒤에 남아 있으면 안 됩니다.
러스트는 빌림 검사기를 통해 이러한 규칙들을 컴파일 시점에 강제합니다. 위험한 참조나 리스크가 있는 변형을 테스트가 잡아내길 바라기보다, 러스트는 메모리를 잘못 쓸 수 있는 코드를 아예 빌드하지 않습니다.
공유 문서를 생각해 보세요:
동시성은 “내 머신에서는 동작한다” 버그가 숨는 장소입니다. 두 스레드가 동시에 실행될 때 특히 공유 데이터를 다루면 놀라운 방식으로 상호작용할 수 있습니다.
데이터 레이스는 다음이 모두 성립할 때 발생합니다:
결과는 단순히 ‘잘못된 출력’이 아니라 상태 손상, 프로그램 충돌, 또는 보안 취약점이 될 수 있습니다. 더 나쁜 것은 간헐적으로 발생하기 때문에 로깅 추가로 사라지는 경우도 많습니다.
러스트는 조금 특이한 입장을 택합니다: 모든 프로그래머가 매번 규칙을 기억한다고 신뢰하기보다, 많은 안전하지 않은 동시성 패턴을 안전한 코드에서 표현할 수 없게 만듭니다.
높은 수준에서, 러스트의 소유권·빌림 규칙은 단일 스레드 코드를 넘어서 공유 가능한 것이 무엇인지에 대한 규칙을 형성합니다. 컴파일러가 공유 접근이 조율되어 있음을 증명할 수 없다면 코드를 컴파일하지 않을 것입니다.
이것이 사람들이 러스트에서 말하는 '안전한 동시성' 입니다: 여전히 동시 프로그램을 작성하지만, ‘어이쿠, 두 스레드가 같은 걸 썼다’ 같은 실수의 많은 범주는 프로그램 실행 전에 잡힙니다.
두 스레드가 같은 카운터를 증가시키는 상황을 상상해보세요:
러스트에서는 단순히 여러 스레드에 가변 접근을 넘기는 것이 안전한 코드에서는 불가능합니다. 컴파일러는 일반적으로 명시적 조정을 요구합니다—잠금 뒤에 상태를 두거나 메시지 전달을 사용하도록 의도를 분명히 하게 합니다.
러스트는 저수준 동시성 기법을 금지하지 않습니다. 대신 그것들을 격리(quarantine) 합니다. 컴파일러가 일반적으로 증명할 수 없는 작업이 필요하면 unsafe 블록을 사용하세요. 이는 코드에 “여기서는 사람의 책임이 필요하다”라는 경고 표식을 다는 것과 같습니다. 이 분리는 코드베이스 대부분을 더 안전한 부분에 남겨두면서도 필요한 곳에서는 시스템 수준의 힘을 허용합니다.
러스트의 안전성 평판은 절대적처럼 들릴 수 있지만, 정확히 말하면 러스트는 안전한 프로그래밍과 위험한 프로그래밍 사이의 경계를 명시적으로 만들고 감시하기 쉽게 합니다.
대부분의 러스트 코드는 ‘안전한 러스트’입니다. 여기서 컴파일러는 use-after-free, double-free, 댕글링 포인터, 데이터 레이스 같은 일반적인 메모리 버그를 막는 규칙을 강제합니다. 여전히 논리적 오류는 쓸 수 있지만, 일반 언어 기능으로 인해 메모리 안전이 자동으로 깨지는 상황은 발생하지 않습니다.
중요한 점: 안전한 러스트가 곧 ‘느린 러스트’는 아닙니다. 컴파일러가 규칙이 지켜진다고 신뢰할 수 있을 때 적극적으로 최적화할 수 있기 때문에 고성능 프로그램이 안전한 러스트로만 작성되는 경우도 많습니다.
unsafe는 컴파일러가 일반적으로 안전성을 증명할 수 없는 능력을 부여합니다. 전형적인 이유는 다음과 같습니다:
unsafe를 사용한다고 해서 모든 검사가 꺼지는 것은 아닙니다. 단지 안전하지 않은 다른 언어 수준의 연산(예: 원시 포인터 역참조)을 허용하도록 작은 집합의 작업을 허용합니다.
러스트는 unsafe 블록과 unsafe 함수에 표시를 요구해 위험을 코드 리뷰에서 가시화합니다. 보통 패턴은 작은 ‘unsafe 핵심’을 안전한 API로 감싸서 프로그램 대부분이 안전한 러스트에 머물도록 하는 것입니다.
unsafe를 전동공구처럼 다루세요:
unsafe 블록은 작고 국소화하세요.\n- 안전성 가정(assumptions)을 명확히 적은 주석을 쓰세요.\n- unsafe 변경에는 추가 리뷰를 요구하세요.\n- 스트레스 테스트 등 검증을 추가하세요.잘 쓰면 unsafe는 시스템 프로그래밍의 수작업 정밀성이 필요한 부분에 대한 통제된 인터페이스가 되고, 코드의 나머지 부분에서 러스트의 안전 이점을 유지하게 합니다.
러스트가 ‘실제’가 된 것은 아이디어가 훌륭해서가 아니라 Mozilla가 그 아이디어를 실무에 눌러 본 덕분입니다.
Mozilla Research는 성능이 중요한 브라우저 구성요소를 더 적은 보안 버그로 만들 방법을 찾고 있었습니다. 브라우저 엔진은 신뢰할 수 없는 입력을 파싱하고, 많은 메모리를 관리하며, 높은 동시성 하에서 동작합니다. 이런 조합은 메모리 안전성 결함과 경쟁 상태를 빈번하고 비용 높게 만듭니다.
러스트 지원은 그 목표와 맞아떨어졌습니다: 시스템 프로그래밍의 속도를 유지하면서 취약성의 전체 범주를 줄이자. Mozilla의 참여는 또한 러스트가 그레이든 호어의 개인 실험을 넘어서서 지구상에서 가장 까다로운 코드베이스 가운데 하나에서 시험될 수 있는 언어임을 알리는 신호였습니다.
실험용 브라우저 엔진인 Servo는 러스트를 대규모로 시험해 볼 수 있는 고프로필 장소가 되었습니다. 목표는 브라우저 시장을 ‘이기는’ 것이 아니라, 실제 제약(빌드 시간, 크로스 플랫폼 지원, 개발자 경험, 성능 튜닝, 병렬성 하의 정확성 등)에서 언어 기능과 컴파일러 진단, 도구를 평가하는 것이었습니다.
중요한 점은 Servo가 언어 주변의 생태계(라이브러리, 빌드 도구, 관례, 디버깅 관행)를 형성하는 데도 기여했다는 것입니다. 장난감 프로그램을 넘어설 때 중요한 것들입니다.
실제 프로젝트는 언어 설계가 흉내 낼 수 없는 피드백 루프를 만듭니다. 엔지니어들이 마찰을 겪을 때—불친절한 오류 메시지, 누락된 라이브러리, 어색한 패턴—그 고통은 빠르게 표출됩니다. 시간이 지나면서 이런 지속적 압력이 러스트를 유망한 개념에서 신뢰 가능한 대규모 소프트웨어용 선택지로 성숙하게 만들었습니다.
이 단계 이후 러스트의 더 넓은 진화를 살펴보고 싶다면 /blog/rust-memory-safety-without-gc 를 참고하세요.
러스트는 중간 지대에 위치합니다: C/C++가 제공하는 성능과 제어를 목표로 하되, 그 언어들이 일반적으로 인간의 규율, 테스트, 운에 맡기는 많은 버그들을 제거하려고 합니다.
C와 C++에서는 개발자가 메모리를 직접 관리합니다—할당, 해제, 포인터의 유효성을 보장해야 합니다. 그 자유는 강력하지만 use-after-free, double-free, 버퍼 오버플로우, 미묘한 수명 버그를 쉽게 만들 수 있습니다. 컴파일러는 일반적으로 당신을 신뢰합니다.
러스트는 그 관계를 뒤집습니다. 여전히 저수준 제어(스택 vs 힙 결정, 예측 가능한 레이아웃, 명시적 소유권 이전)를 얻지만, 컴파일러는 값의 소유자와 참조의 유효 기간에 대한 규칙을 강제합니다. 러스트는 ‘포인터를 조심해라’가 아니라 ‘컴파일러에게 안전을 증명하라’고 말하며, 안전한 러스트에서는 그 증명이 불가능한 코드를 컴파일하지 않습니다.
가비지 컬렉션 언어(예: Java, Go, C# 등)는 수동 메모리 관리를 편의성으로 교환합니다: 객체는 더 이상 도달 불가능할 때 자동으로 해제됩니다. 이는 생산성에 큰 도움이 됩니다.
러스트의 약속인 “가비지 컬렉터 없이 메모리 안전성”은 런타임 GC의 비용을 지불하지 않으면서도 지연, 메모리 사용량, 시작 시간, 제약 환경에서 유리합니다. 트레이드오프는 소유권을 명시적으로 모델링하고 컴파일러가 그것을 강제하게 하는 것입니다.
러스트는 처음엔 어렵게 느껴질 수 있습니다. 소유권, 빌림, 수명이라는 새로운 사고 모델을 배우기 때문입니다. 공유 상태나 복잡한 객체 그래프를 모델링할 때 초기 마찰이 자주 나타납니다.
러스트는 보통 보안 민감하고 성능이 중요한 소프트웨어(브라우저, 네트워킹, 암호화, 임베디드, 엄격한 신뢰성이 필요한 백엔드 서비스)에 강점을 보입니다. 만약 팀이 빠른 반복 개발을 최우선으로 하고 저수준 제어가 덜 중요하다면 GC 언어가 더 맞을 수 있습니다.
러스트는 보편적 대체재가 아니라, C/C++급 성능과 의지할 수 있는 안전 보장을 동시에 원할 때 강력한 선택지입니다.
러스트는 ‘더 멋진 C++’로 주목받은 것이 아니라, 저수준 코드가 빠르면서, 메모리-안전성이 있으며, 비용을 명시적으로 드러낼 수 있다는 점을 고집함으로써 대화를 바꿨습니다.
러스트 이전에 팀들은 메모리 버그를 성능의 대가로 치러야 하는 세금으로 여겼고, 테스트·코드 리뷰·사후 처치에 의존했습니다. 러스트는 다른 선택을 제시했습니다: 데이터 소유권, 변경 권한, 참조 유효성 같은 공통 규칙을 언어에 인코딩해, 전체 범주의 버그를 컴파일 시점에서 거부하게 한 것입니다.
그 전환은 개발자들에게 ‘완벽해지라’고 요구하는 대신 ‘명확해지라’고 요구했고, 컴파일러가 그 명확함을 강제하도록 했다는 점에서 의미가 큽니다.
러스트의 영향은 단일 헤드라인이 아니라 여러 신호에서 드러납니다: 성능 민감한 소프트웨어를 배포하는 회사들의 증가하는 관심, 대학 강좌에서의 등장, 일상적으로 쓰기 좋은 도구들(패키지 관리, 포맷터, 린터, 문서화 워크플로우)의 개선 등.
이 모든 것이 러스트가 항상 최선의 선택이라는 뜻은 아니지만, ‘기본적으로 안전을 기대하는 것’이 사치가 아니라 현실적인 기대가 되었다는 점은 분명합니다.
러스트는 보통 다음과 같은 경우에 평가됩니다:
‘새 표준’은 모든 시스템이 러스트로 다시 작성된다는 뜻이 아닙니다. 대신 기준선이 이동했다는 의미입니다: 팀들은 점점 ‘왜 메모리-안전하지 않은 기본값을 받아들여야 하는가?’라고 묻습니다. 러스트를 채택하지 않을 때조차도, 그 모델은 더 안전한 API와 명확한 불변식, 올바른 정확성 도구를 중시하도록 생태계를 밀어왔습니다.
관련 엔지니어링 배경 이야기를 더 보고 싶다면 /blog를 둘러보세요.
러스트의 기원 이야기는 단선적입니다: 한 개인의 사이드 프로젝트(그레이든 호어의 언어 실험)가 골치 아픈 시스템 프로그래밍 문제와 정면으로 부딪혔고, 그 해결책은 엄격하면서도 실용적이라는 점에서 성공을 거뒀습니다.
러스트는 많은 개발자가 불가피하다고 가정하던 트레이드오프를 재구성했습니다:
실질적 변화는 단순히 ‘러스트가 더 안전하다’가 아니라 안전성이 언어의 기본 속성이 될 수 있다는 점입니다. 더 이상 코드 리뷰와 테스트에만 의존하는 선택지가 아닙니다.
호기심이 있다면 큰 리라이트 없이도 러스트의 느낌을 경험할 수 있습니다.
작게 시작하세요:
부드러운 경로를 원하면 ‘파일을 읽고, 변환하고, 출력 쓰기’ 같은 얇은 슬라이스 목표를 택해 명확한 코드를 쓰는 데 집중하세요.
대규모 제품 안에 러스트 컴포넌트를 시범적으로 넣을 때는 주변(관리 UI, 대시보드, 제어 평면, 간단한 API)은 빠르게 개발하고 핵심 시스템 로직은 엄격하게 유지하는 패턴이 도움이 됩니다. Koder.ai 같은 플랫폼은 채팅 기반 워크플로로 React 프런트엔드, Go 백엔드, PostgreSQL 스키마를 빠르게 생성해 러스트 서비스와 깔끔한 경계로 통합하는 ‘글루’ 개발을 가속할 수 있습니다.
두 번째 글에서 어떤 내용이 가장 유용할까요?
unsafe를 책임감 있게 쓰는 방법\n- C/C++ 팀이 단일 컴포넌트에 러스트를 고려할 때의 비교 가이드당신의 상황(무엇을 만드는지, 현재 어떤 언어를 쓰는지, 무엇을 최적화하려는지)을 알려주시면 다음 섹션을 그에 맞춰 맞춤화하겠습니다.
시스템 프로그래밍은 하드웨어와 제품의 위험 지점에 가깝게 위치한 작업을 뜻합니다. 예로는 브라우저 엔진, 데이터베이스, 운영체제 구성요소, 네트워킹, 임베디드 소프트웨어 등이 있으며,
일반적으로 예측 가능한 성능, 저수준 메모리/제어, 그리고 높은 신뢰성을 요구하는 영역입니다. 충돌이나 보안 버그 발생 비용이 특히 크기 때문에 주의가 필요합니다.
이는 러스트가 런타임 가비지 컬렉터에 의존하지 않고도 흔한 메모리 버그(예: use-after-free, double-free 등)를 방지하려는 목표를 의미합니다.
런타임에서 주기적으로 메모리를 수거하는 대신, 러스트는 소유권과 빌림 규칙을 통해 많은 안전성 검사를 컴파일 시점으로 밀어냅니다.
정적 분석기와 같은 도구들이 많은 문제를 잡을 수는 있지만, 언어 자체가 포인터와 수명 패턴을 자유롭게 허용하면 도구만으로 완전한 보장을 제공하기 어렵습니다.
러스트는 핵심 규칙을 언어와 타입 시스템에 녹여 넣어, 필요한 경우 명시적 탈출구를 유지하면서도 컴파일러가 기본적으로 여러 범주의 버그를 거부하도록 설계되었습니다.
GC는 런타임 오버헤드와 특히 예측성이 떨어지는 지연(latency) 를 도입할 수 있습니다(예: 수집으로 인한 일시 중단 등).
브라우저, 실시간에 가까운 컨트롤러, 저지연 서버 등에서는 최악의 경우(worst-case)가 중요하기 때문에, 러스트는 가비지 컬렉터 없이도 안전을 확보하면서 더 예측 가능한 성능을 유지하려는 목표를 세웠습니다.
소유권은 각 값이 ‘정리 책임자(소유자)’ 하나를 갖는다는 뜻입니다. 소유자가 스코프를 벗어나면 그 값은 자동으로 정리됩니다.
이로 인해 누가 언제 메모리를 해제해야 하는지를 수작업으로 추적할 필요가 줄어들고, 두 곳에서 같은 할당을 해제하려는 상황 같은 오류를 방지할 수 있습니다.
‘이동(move)’는 소유권을 한 변수에서 다른 변수로 옮기는 것입니다; 이동 후 원래 변수는 그 값을 사용하면 안 됩니다.
이는 ‘하나의 할당을 두 주체가 소유하는’ 실수를 피하게 해주며, double-free나 use-after-free의 근본 원인을 차단하는 데 도움이 됩니다.
빌림(참조)은 소유권을 넘기지 않고 값을 잠시 사용하는 방법입니다.
핵심 규칙은: 여러 읽기(공유 참조) 또는 하나의 쓰기(가변 참조) — 동시에 둘 다 허용되지 않습니다. 이는 읽는 동안 다른 곳에서 값이 변경되는 상황을 예방합니다.
수명(lifetime)은 ‘참조가 유효한 기간’입니다. 러스트는 참조가 가리키는 데이터보다 오래 존재해서는 안 된다는 요구를 합니다.
빌림 검사기(borrow checker)는 이 규칙들을 컴파일 시점에 강제하여, dangling reference를 만들 수 있는 코드를 빌드하지 못하게 합니다.
데이터 레이스는 여러 스레드가 같은 메모리에 동시에 접근하고(최소 하나는 쓰기), 접근 타이밍에 대한 조율이 없을 때 발생합니다.
러스트는 소유권/빌림 규칙을 동시성 모델에도 적용해, 컴파일러가 공유 접근이 안전하게 조율된다는 것을 증명할 수 없으면 코드를 컴파일하지 않습니다. 따라서 많은 데이터 레이스가 안전한 코드 수준에서 표현 불가능합니다.
대부분의 코드는 ‘안전한 러스트(safe Rust)’로 작성됩니다. 이 환경에서는 컴파일러가 메모리 안전 규칙(예: use-after-free, double-free, 댕글링 포인터, 데이터 레이스)을 강제합니다.
unsafe는 컴파일러가 일반적으로 안전성을 증명할 수 없는 연산을 허용하는 명시적 탈출구입니다(예: FFI, 하드웨어 접근, 일부 성능 최적화). 일반적인 관행은 unsafe를 작고 국소화된 영역에 모아 안전한 API로 감싸는 것입니다.