안녕하세요 ^^
앞서 임시 지역 변수 사용에 따른 성능 측정 결과를 정리한 글에 이어
한 가지 "구체적인 사용 요령"을 추가로 올립니다.
변수의 scope를 최소화 하자 !
저는 이전에 C 개발이 주특기(?)였습니다.
C++도 꽤 하기는 했으나, 상당히 C 스타일의 C++에서 크게 벗어나질 못했습니다.
Java도 알고는 있었지만 거의 안 쓰다가 안드로이드 오면서 본격적으로 Java를 하게 되었습니다.
저와 같은 분들의 특징은 지역 변수 선언을 함수 초반에 몰아 넣는 (나쁜) 습관이 있다는 것입니다.
예를 들어 보겠습니다.
void testFunc() {
int left = getLeft();
int right = getRight();
// left를 써서 계산하는 코드 (이 부분에서 right는 전혀 쓰지 않음)
...
...
// right를 써서 계산하는 코드
...
...
}
이런 코드는 가독성이 떨어지므로 절대 좋은 습관이 아닙니다.
left를 써서 계산하는 코드 부분이 상당히 복잡하다고 합시다.
그러면, right가 중간에 쓰였는지 안쓰였는지,
right값에 새로운 값을 써서 중간에 값이 바뀌지는 않았는지...
한눈에 파악이 안됩니다.
대신 아래와 같이 쓰면...
void testFunc() {
int left = getLeft();
// left를 써서 계산하는 코드 (이 부분에서 right는 전혀 쓰지 않음)
...
...
int right = getRight();
// right를 써서 계산하는 코드
...
...
}
left를 써서 계산하는 코드 부분에서 right값을 사용하지도 바꾸지도 않았다는 사실이 분명해집니다.
선언을 초반에 몰아 쓴다고 해서 조금도 더 빨라지지 않습니다.
지역 변수는 사용 직전에 선언하고 초기화 합시다.
심지어 이런 예도 있습니다.
int value;
int size = mList.size();
for (int i = 0; i < size; i++) {
value = mList.get(i);
// value를 써서 계산하는 코드
...
...
}
// 이 뒤에도 코드가 계속되지만 value 변수는 더 이상 사용하지 않음
...
...
이것 보다는 아래와 같은 코드가 조금 더 좋습니다.
int size = mList.size();
for (int i = 0; i < size; i++) {
int value = mList.get(i);
// value를 써서 계산하는 코드
...
...
}
// 이 뒤에도 코드가 계속되지만 value 변수는 더 이상 사용하지 않음
...
...
이번에는 for 루프 바깥에 변수를 선언하지 않고, 루프 안에서 value를 선언했습니다.
value는 for 루프 안에서만 사용되는 변수기 때문에 scope를 최소화 하기 위해서 이렇게 했습니다.
처음 코드는 for 루프가 끝난 후
뒤에 이어지는 코드에서는 value가 더 이상 필요하지 않지만
변수는 계속해서 유효하기 때문에 별로 좋지 않습니다.
문제는...
"저렇게 변수를 자주 선언하면 더 느려지지 않나요? ㅠㅡㅠ" 입니다.
느낌상 정말 엄청 느려질 것 같습니다만...
사실 루프 내에서 변수를 선언한다고 해서 더 느려지지는 않습니다.
걱정하지 않으셔도 된다고 합니다.
이에 대한 자세한 설명은 아래 글을 참고하시기 바랍니다. :)
http://benelog.springnote.com/pages/386996
정말 유익한 글이니 한 번 쯤 시간을 내어 꼭 읽어보시기 바랍니다.
안드로이드 개발자 사이트의 글은 저도 읽어보았습니다. ^^
유익하더군요~
말씀하신 부분은 상당부분 동의합니다만...
int, double 같은 primitive type과 object type의 차이가 있을 것 같습니다.
안드로이드 개발자 사이트에서도 분명히 "avoid creating unnecessary objects" 라고 하고 있지요.
언급하고 있는 예도, 배열이나, class, string 같은 것으로 예를 들고 있지,
int, double 같은 primitive type 지역 변수에 관한 언급은 없습니다.
게다가 "creating"입니다. 그냥 객체를 참조만 하는 경우도 해당사항 없는 것 같습니다.
예를들어...
View v = getChildAt(0);
이런 경우 v 는 객체를 creating하는건 아니지요.
이런 종류의 지역 변수도 상관없을 듯 합니다.
다양한 포스트와 글을 읽어본 제 나름의 결론은
primitive type의 지역 변수를 많이 쓴다고 해서 user experience에 해가 되는 끈김 현상은 없을 것 같습니다.
물론 정답은 모르겠습니다. ^^
제 의견입니다...
저도 비슷한 의견입니다.
JVM에서 보면 로컬변수는 Stack이라는 영역에서 할당되어 메소드가 종료되는 시점에 바로 메모리에서 할당이 없어지는데 비해
인스턴스나 array등은 heap 영역에 할당되어 가비지 콜렉션의 대상이 되지요.
스트링의 경우는 intern 인가 하는 동작으로 다른 영역을 사용하는 것으로 알고있습니다. 이건 가물가물하네요;;;
달빅 vm은 제대로 본 적이 없긴 하지만(-_-) 이부분에 있어서는 큰 차이가 없을 거라고 예상이 되고,
gc 대상이 되지않는 변수 선언은 메모리 성능에 영향이 (거의)없는 것이 맞습니다.
아랫 글에 "봉느님"님이 걸어두신 링크 읽어보고 댓글 답니다.
http://developer.android.com/guide/practices/design/performance.html
"Avoid Creating Unnecessary Object" 이 부분입니다.
불필요한 임시변수가 생성되면 GC가 너무 빈번히 발생되서
(물론 진저에서 GC 성능향상이 있었습니다만)
user experience에 악영향을 끼칠 수 있다고 경고하고 있습니다.
특히 user interface loop에서는 "hiccups", 즉 딸꾹질같은 끈김이 발생할 수 있다고 합니다.
모바일의 특성상, 실행 속도보다는 user experience가 더 중요한게 아닐까 합니다.
ps. 저 링크는 안드로이드 개발자라면 꼭 읽어봐야할 내용인것 같습니다.
개발자 싸이트에 좋은 내용이 많은것 같네요.
언젠가는 시간을 내서 정독을 해야 할 것 같은 느낌.