DFS 문제를 풀며
DFS 문제를 공부하며, 예제 코드를 봤는데, graph 변수를 전역변수로 선언하고 사용하고 있었다. 컴퓨터구조를 공부하면서, 전역변수는 메모리에 할당되고 함수의 일부 매개변수는 레지스터에 저장되어 훨씬 빠른 속도로 액세스된다고 이해했었다. 그렇다면 graph 변수를 dfs 함수의 인자로 넘겨줄 때, ‘전역변수를 사용하지 않고 매개변수로 넘겨주면 성능이 더 좋은 코드가 되지 않을까?’ 라는 궁금증에 휩싸여 풀던 문제를 내려놓고 열심히 구글링을 하기 시작하였다.
기존에 알고 있던 것
우선 두가지 생각을 했다. 첫번째, 전역변수는 메모리에 올라가기 때문에 액세스가 느리다. 두번째, 매개변수는 지역변수이지만, 재귀함수처럼 호출이 잦다면 해당 매개변수를 할당하고 해제하는 작업을 반복하면서 느려질 것이다. 첫번째 의견에 대해서는 지역변수의 액세스보다 전역변수의 액세스가 느리다는 것은 대충 ‘그렇게 들었다~’ 수준으로 알고 있었다. 두번째 의견은 컴퓨터 구조를 공부하며 어셈블리 코드에 대해서도 아주 살짝 공부를 했었는데, 함수를 호출하는 부분에서 매개변수의 할당과 해제에 대한 어셈블리 코드가 없다는 것은 알고 있었다. 그렇기 때문에 ‘함수의 호출이 잦아도 매개변수의 할당과 해제로 실행속도가 느려지거나 하진 않을 것이다.’ 라는 결론을 내렸지만, 이 의견이 맞는지 조금 불안했다.
전역변수와 지역변수의 저장 위치
구글링의 결과, 전역변수와 함수로 인해서 호출된 지역변수는 모두 메모리에 위치한다. 하지만, 전역변수는 메모리에서 상대적으로 낮은 위치인 데이터 영역에 저장되고, 지역변수는 상대적으로 높은 위치인 스택 영역에 저장된다. 데이터 영역은 프로그램 끝나기 전까지 해제되지 않고, 스택 영역은 해당 함수가 리턴되면 해제된다. 또한 데이터 영역보다 스택 영역의 액세스가 빠르다.
캐시 적중
해당 데이터가 캐시 위에 올라와 있을 확률은 최근에 사용된 적이 있는 지역 변수쪽이 전역 변수쪽보다는 높다. 전역 변수는 비슷한 위치의 주소공간에 존재한다는 보장이 없다. 반대로 지역변수의 경우는 스택에 쌓이기 때문에, 모두 비슷한 위치에 존재한다. 결국 지역변수들은 한 캐시 블록 안에 올라가 있을 확률이 매우 높다.
컴파일러 최적화
C언어 기준으로, 전역 변수는 최적화에 불리하다. 전역 변수는 언제 그 값이 변경되는지 알 수 없기 때문에, 컴파일러가 최적화를 진행할 때 전역 변수를 제거하지 않는다. 즉, 컴파일러가 사용자의 의도를 모르기 때문에, 최적화를 하지 못하고 그대로 코드를 남겨둔다.
결론 : 매개변수가 전역변수보다 빠르다.
물론 모든 상황에서 매개변수로 전달하는 것이 전역변수보다 빠르지 않을 수 있다. 특정 블로그에서 실험했을 때 매개변수로 전달된 변수들을 전역변수로 변경하니 실행 시간이 2배 정도 향상되었다고 한다. 하지만, 최적화를 위해서 전역변수를 사용하는 것은 잘못된 방법이며, 더 적절한 알고리즘과 자료구조를 사용하는 것이 옳다. 물론 간단한 코드에서 전역변수로 전달을 하냐 매개변수로 전달을 하냐에 대해 아주 미미한 속도 차이 혹은 차이가 없을 수도 있겠지만, 항상 이러한 생각을 가지며 혹시 모를 병목 현상을 예방하는 것이 더 나은 프로그래머가 될 수 있는 길이라고 생각한다.
댓글남기기