본문으로 바로가기
TaeyoungKim.dev

Dart compile exe 실행 파일이 안 바뀌는 이유: JIT·AOT 차이

앱작성 약 4분 읽기TaeyoungKim
LinkedInX

코드에서 v1을 v2로 바꿨다. dart run은 v2를 보여 주는데, 어제 만든 실행 파일은 여전히 v1이라고 한다. 저장 버튼을 안 눌렀나 싶어 파일을 다시 열어 봐도 v2가 맞다. 바뀐 것은 소스이고, 실행 파일은 아직 예전 소스로 만든 결과물이기 때문이다.

이 차이를 이해하면 Dart의 JIT·AOT를 '빠른 것과 더 빠른 것'처럼 외우지 않아도 된다. 같은 파일을 두 방식으로 실행한 뒤 한 줄만 고쳐 보자.

dart run과 dart compile exe는 무엇이 다를까?

dart run은 Dart VM에서 프로그램을 실행한다. 개발 중에는 실행 시점의 JIT(Just-in-time) 컴파일을 이용하므로 다음에 다시 실행할 때 현재 소스를 읽는다. dart compile exe는 소스를 미리 AOT(Ahead-of-time) 컴파일해 별도 실행 파일을 만든다. Dart의 컴파일 명령 설명은 dart run의 JIT 실행과 compile exe의 독립 실행 파일을 이처럼 구분한다.

여기서 핵심은 속도 순위가 아니라 언제 어떤 코드를 실행 파일에 담았는가다. dart run을 다시 호출하는 일과 이미 만들어 둔 파일을 다시 호출하는 일은 다르다. 단, dart run을 한 번 실행한 프로세스가 소스 변경을 자동 감지해 갱신되는 것은 아니다. 다시 실행해야 새 소스를 읽는다. Flutter의 hot reload와도 같은 명령으로 취급하면 안 된다.

소스를 고쳤는데 기존 실행 파일이 v1인 이유

다음 내용을 app.dart에 저장한다. build는 어느 버전의 소스로 만들었는지 눈에 보이게 하려는 표시다. review는 실행할 때 전달하는 인수다.

dart
void main(List<String> args) {
  const build = 'v1';
  final action = args.isEmpty ? 'read' : args.first;
  print('$build: $action');
}

먼저 소스를 실행하고, 같은 소스로 실행 파일을 만든다.

bash
dart run app.dart review
# v1: review

dart compile exe app.dart -o app
./app review
# v1: review

이제 app.dart의 const build = 'v1';만 const build = 'v2';로 고친다. 다른 코드는 그대로 둔다.

bash
dart run app.dart review
# v2: review

./app review
# v1: review

실행 파일이 소스를 못 읽어서 고장 난 게 아니다. 처음 dart compile exe를 실행한 시점의 소스로 만든 파일을 정확히 실행하고 있다. 소스를 바꿀 때마다 기존 실행 파일까지 자동 수정되는 것은 아니다.

수정한 코드를 실행 파일에 반영하려면?

같은 명령으로 다시 컴파일한다.

bash
dart compile exe app.dart -o app
./app review
# v2: review

배포 스크립트에서도 같은 원칙을 적용한다. 소스 커밋만 바뀌었는지, 실제로 배포할 바이너리가 그 소스로 다시 만들어졌는지를 구분해야 한다. 오래된 실행 파일을 배포하면 소스 저장소에는 수정 내용이 있어도 사용자에게는 이전 동작이 보인다. 이럴 때는 dart run의 결과와 배포 파일의 결과를 같은 인수로 비교하고, 빌드 단계를 다시 확인한다.

review 인수는 컴파일할 때 고정되지 않는다. 예를 들어 기존 v1 실행 파일에 publish를 전달하면 v1: publish가 나온다. AOT는 프로그램 코드를 미리 컴파일한다는 뜻이지, 모든 실행 시점의 입력까지 미리 정한다는 뜻은 아니다.

AOT 실행 파일이면 무조건 더 빠르고 어디서나 실행될까?

compile exe 결과에는 실행에 필요한 작은 Dart 런타임이 포함되지만, 대상 운영체제와 CPU 아키텍처에 맞는 파일이다. 한 컴퓨터에서 만든 파일을 모든 플랫폼에서 그대로 실행할 수 있다는 뜻은 아니다. 배포 대상에 맞는 빌드와 실행 확인이 필요하다.

JIT는 개발 중 변경을 빠르게 시험하기 좋고, AOT 실행 파일은 실행 전에 코드가 컴파일된 산출물을 배포할 때 유용하다. 그렇다고 이 네 줄짜리 예제로 'AOT가 언제나 몇 배 빠르다'라고 결론 내릴 수는 없다. 시작 시간과 반복 실행 성능, 빌드 시간은 서로 다른 지표다. 성능이 선택 기준이라면 실제 앱과 배포 환경에서 따로 측정하자.

핵심 요약

dart run은 다시 실행할 때 현재 소스를 사용한다. dart compile exe로 만든 파일은 컴파일 당시 소스의 결과물이므로, 소스를 수정했다면 다시 컴파일해야 반영된다. 실행 파일에 전달하는 인수 같은 런타임 입력은 여전히 바꿀 수 있다. 결과가 엇갈릴 때는 '어느 파일을 언제 빌드했는가'부터 확인하자.

작성자

TaeyoungKim

기초 개념을 구현과 검증, 실제 운영 판단까지 연결해 기록합니다.

#Dart#Dart JIT AOT 차이#dart run#dart compile exe#Dart 실행 파일#재컴파일

함께 읽으면 좋은 글