Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

포메

[flutter (dart)] const를 많이 쓰는 건 이익일까? 손해일까? (런타임 RAM 메모리 영역과 성능에 관하여) 본문

dart & flutter

[flutter (dart)] const를 많이 쓰는 건 이익일까? 손해일까? (런타임 RAM 메모리 영역과 성능에 관하여)

포포메 2025. 3. 1. 01:40

 
flutter로 코딩을 처음하면 다음과 같은 경고 문구를 자주 본다.

 
이 경고 문구는 flutter, dart의 자체적인 linter가 알아서 감지하고 수정해 준다.
불변하는 위젯에 대해 const로 선언하여 런타임 렌더링/빌드 성능을 올리라는 추천이다.
 
처음에는 별 생각 없이 추천을 따르긴 했다. 성능적 이점이 확실히 검증됐기 때문에, linter에서 이렇게 강한 수정이 들어가는 것이라고 단순히 생각했다.
이제는 플러터에 많이 익숙해졌고, 어떤 측면에서 어떠한 성능적 이점이 있는지 디테일이 궁금해졌다.
그래서 공부를 좀 해봤다!
 
 

flutter의 const 위젯은 런타임 RAM의 data 영역에 저장되는 불변 상수이다.

즉, 통상적인 프로그래밍 언어의 "전역 변수"와 유사한 취급을 받는다.
 
통상적으로 이러한 "전역 변수"는 (당연하게도) 말 그대로 변수들을 다룰 때 사용된다.
 
그러나
flutter는 특이하게도 일부 위젯까지 const 처리를 추천하여, 전역 변수와 유사한 메커니즘으로 사용되게 설계되었다. 
 
 
해당 위젯들은
컴파일 타임에 크기가 계산되며, 그 크기가 변하지 않고 고정적이다.
또한 런타임 실행 시 최초의 순간에 RAM의 data 영역에 저장되고, 프로그램 종료 시점까지 고정적인 메모리 영역을 차지한다.
 
 
위와 같은 정보를 들으면 다음과 같은 생각을 해볼 수 있을 거 같다.
 
그런데 RAM의 공간은 제한적인 만큼, 최대한 아껴써야 하는 거 아닌가 ??
 
 
이렇게 생각해보면 const는 단점이 많아 보인다. 런타임의 RAM을 아껴쓰는 게 중요한데, 고정적인 RAM 메모리 영역을 차지하면 안 좋은 거 아닌가?? 그런데 왜 flutter linter는 const를 강하게 추천하는 거지??
 
이런 생각이 들 수 있을 것 같다. (최소한 나는 위와 같은 생각이 들었었다.)
 

data 영역을 과하게 쓰면 이론 상 손해가 될 수도 있다. 그러나 이익이 될 확률이 높다.

 
"런타임에 고정적인 메모리 영역을 차지한다."를 다른 말로 표현하면
 
"여러 번 반복 사용하는데 유리하다."라고 볼 수도 있다!
 
왜 ?? : 통상적으로 RAM의 Stack 영역, Heap 영역을 넘나드는 지역변수들의 동작 메커니즘과 비교해보면,
위와 같이 생각할 수 있다.
 
Stack, Heap의 대표적인 특징이 뭔가 ????
메모리 Garbage Collector가 작동한다는 것. 즉 사용할 때 메모리가 할당되고, 사용하지 않을 때 메모리가 해제된다.
 
사실 메모리 할당과 해제는 필수적이긴 하다.
RAM의 용량은 제한적이고, 코드의 규모는 무한히 커질 수 있는데,
런타임. 현재 이 순간과 관련된 메모리만 할당하고, 관련 없는 메모리는 해제하는 것이 당연한 접근법이다. 
 
물론. 당연히 해야한다는 것이지 비용이 없다는 것은 아니다.
할당과 해제, Garbage Collector를 작동시키는 것도 당연히 비용이다.
워낙 자주 일어나는 만큼 큰 비용은 아니고, 매우 효율적으로 작동하지만, 
 
굉장히 고빈도로 사용되는 메모리를 과하게 자주 할당하고 해제한다면, 그건 쓸데 없는 낭비일 가능성은 항상 있을 것이다.
 
이건 TradeOff이다. 이것이 포인트다.
만약 앱에 전역적으로, 충분히 자주 사용되는 변수가 있다면,
 
그것이 고정적인 메모리를 점유하도록 하는 것이 더 효율적인 선택일 수 있다.
굳이 메모리 할당, 해제를 반복하지 않는 것이 더 효율적인 선택일 수 있다.
고정으로 점유하고 있는 메모리를 단순히 읽는 것이 더 효율적이기 때문.
 
추가적으로, 정말 여러 번 사용되는 const들은 CPU 레지스터 상에 캐싱되어 최적화가 될 가능성도 커진다. 
 
이론 상. 가장 읽고 쓰는 비용이 효율적인 메모리 영역은 CPU 레저스터로 알고 있다.
const가 자주 레지스터에 넘나들 경우,
이미 지금 이 순간에 레지스터에 존재하는 const를 2번, 3번 반복 사용할 경우.
 
그때마다 효율이 상승할 것이다. 가장 효율적으로 메모리를 읽은 것이기 때문.
 
물론 레지스터와 관련한 이득은 단순히 추정하고 기대하는 것이지, 개발자가 직접적으로 제어하고 관여하는 부분은 아니다!
 
 
 
그런데
주제를 살짝 바꿔서
 

(이론 상) RAM을 고정 점유하는 const가 RAM의 영역을 과하게 혹은 전부 차지할 수 있는 거 아닌가 ??

 
이론 상 그럴 수도 있을 거 같다.
물론 이론 상이지, 쉽지는 않을 거 같다 ㅋㅋㅋ
RAM이 최소 8기가, 16기가, ... 라고 했을 때
const Text('Hello World') 이런 거 모아서 1MB를 채우는 것도 만만치는 않을 것.
 
아무튼 앱의 규모는 이론 상 무한하기 때문에.
정말 초거대 앱에서 const가 8기가 존재하면 ?? 그건 문제가 될 것으로 예상된다.
 
그러나 flutter 개발자들이 이런 부분은 충분히 테스트를 해보고, 위젯에 대한 const화라는 신선한 개념을 도입하지 않았을까 싶다.
그들이 테스트해봤을 때 경험적으로 대부분의 상황에 문제가 없었기 때문에 linter로 강하게 제안하고 있을 것이라고 믿고,
일단은 사용해도 큰 문제 없을 것으로 예상된다.
 
 
어떻게 얼마 만큼 써야 효율적일지, 왜 const를 맘 편히 써도 될지에 관한 이해를 위해
다음과 같이 재사용의 개념을 정교화하면 도움이 될 것 같다.
 
 

const는 꽤 자주, 알아서 재사용되고 공유된다.

재사용의 범주를 명확하게 해야 할 것 같다. 다음 예시를 보면 쉽게 이해될 것 같다.
 

재사용이 되는 경우

const w1 = Text('hello');
const w2 = Text('hello');

print(identical(w1, w2)); // true

 
사람이 적어놓은 변수명은 서로 다르지만, 내부의 실질적인 컨텐츠가 완전히 동일하다. 동일한 Text 위젯이고, 동일한 'hello'라는 내용. 따로 style도 없고 완전히 동일하다. 이럴 경우에
const가 전역 범위에서 재사용되는 것이다. 
 
만약 Text('hello')를 2번 이상 변수에 할당하거나, 2번 이상 렌더링 한다면 그때부터 const의 이점이 시작될 것이다.
 
앱의 규모가 커진다면, 위와 같은 작은 위젯들이 겹치는 경우가 생각보다 많이 나올 수 있을 거 같다.
 
곳곳에, 구석구석, Text('hello') 같은 건 꽤 여러 번 나올 수 있을 것으로 추정되며, 그때마다 메모리를 1/2, 1/3로 사용하는 효과를 보는 것.
 

재사용이 되지 않는 경우

const w1 = Text('hello');
const w2 = Text('hi');

print(identical(w1, w2)); // false

 
둘은 동일한 Text 위젯이긴 하다. 그렇지만 내부의 값이 'hello', 'hi'로 다르다. 이럴 경우 완전히 동일한 건 아니라서 재사용 할 수 없다.
 
 
 

(final과 다르게) 리빌드 시에도 재사용된다. (빌드 메서드 내부의 위젯,  변수)

사실 전역적 재사용의 연장선에 있는 개념이다.
 
리빌드는 State가 변경될 때 일어난다.
statefulWidget or provider 등등에 관련된 UI 및 변수들의 경우 항상 리빌드의 가능성을 가지고 있다.
 
const는 전역적으로 메모리 공유가 되는 만큼 여러 번의 리빌드를 해도 메모리를 재사용한다.
반면 final로 선언된 변수가 빌드 메서드 내부에 있을 경우, 매번 새로운 메모리를 할당한다.
 
물론 빌드 메서드 바깥에 있는 객체들은, final이어도 메모리 해제 및 재할당의 작업을 하지 않을 것이다.
 
아무튼 리빌드 간 메모리가 재사용된다면 2가지 부수적인 이익이 있다.
1. 메모리 재할당의 비용 감소 (새로운 객체 생성의 비용 감소)
2. GC를 덜 작동시키기 때문에, GC의 비용 감소.
-> 재사용의 빈도가 늘어날 수록 위 장점들은 커짐.
 

const 사용으로 인한 런타임 성능 향상이 사실상 없는 경우

 
내가 위에서 언급한 장점의 케이스에 "하나도" 걸리지 않는다면 성능 향상은 사실상 없다고 봐도 될 거 같다.
앱 전체가 statelessWidget (리빌드가 0회)
3 + 4와 같이, const에 종속된 연산도 전혀 없는 상태
모든 위젯과 변수의 값이 다 다른 상태. (Text('hi1'), Text('hi2') 등등 미묘하게 다른 객체들만 존재하는 상태)
 
위 모든 조건이 겹친다면 성능 향상은 사실상 없을 것.
 
하지만 ㅋㅋㅋㅋㅋ 그런 앱은 사실상 없지 않을까 싶다.
경험적으로 확률이 적기 때문에, flutter 개발자들이 이러한 설계를 했을 것이다.
 

추가 팁

 
서두에서 flutter linter가 위젯의 const는 보정해준다고 언급했었다.
근데 20250228 기준까지의 linter는 일반 변수에 대해서는 보정해주지 않는 것으로 알고 있다.
 
위와 같은 const의 손익을 계산하여, 필요하다면 일반 변수들도 const 처리해도 될 것이다.
충분히 자주 사용되는지 알아서 잘 판단하고 최적화하는 것이 개발자의 역량일 것!!
 
 
빠이