[JAVA]컴파일 최적화,compile optimization

무지성개발자·2023년 8월 14일
0

컴파일 최적화

컴파일 최적화는 소스 코드를 컴파일 할 때 더 효율적으로 변환하기 위한 과정이다. 이 과정에서 컴파일러는 프로그램의 실행 속도를 향상시키거나 메모리 사용량을 줄이는 등의 목적으로 코드를 변경하거나 최적화한다.

컴파일 최적화의 목적

  • 성능 향상 : 프로그램의 실행 속도를 높여 빠른 실행.(ex. 불필요한 코드 제거, 루프 언롤링, 인라인 함수 확장)

  • 메모리 관리 : 프로그램이 사용하는 메모리 양을 최소화하여 시스템의 메모리 자원을 효율적으로 사용.(ex. 변수들의 레지스터 할당, 불필요한 변수 제거)

  • 코드 크기 감소 : 불필요한 코드나 중복 코드를 제거하여 실행 파일의 크기를 최소화.

  • I/O 최적화 : 입출력 작업을 최적화하여 파일 또는 네트워크와의 상호 작용을 더 효율적으로 수행.

컴파일 최적화 예시

컴파일 타임 상수 폴딩

public static void main(String[] args) {
    int result = 10 * 5;  // int result = 50으로 판단
    System.out.println(result);
}

런타임에 연산을 하지 않고 컴파일 시 결과 작성.

불필요한 코드 제거

public static void main(String[] args) {
    int x = 10;
    if (x > 5) {
        System.out.println("x is greater than 5");
    } else { //이 블록은 실행 안함
        System.out.println("x is not greater than 5");
    }
}

사용되지 않거나 도달 할 수 없는 코드는 제거함.

인라인 함수 호출

public static int add(int a, int b) {
    return a + b;
}

public static void main(String[] args) {
    int result = add(3, 5);  // int result = 3 + 5로 대체
    System.out.println(result);
}

메서드를 실행 시키면 스택에 불러들여와 사용후 pop()과정 까지 거쳐야 하는데 간단한 메서드의 경우 코드를 그냥 불러와서 적용시킴.

루프 언롤링

public static void main(String[] args) {
    int[] arr = new int[3];
    for (int i = 0; i < 3; i++) {
        arr[i] = i;
    }
    // for 문을 아래와 같이 대체
    a[0] = 0;
    a[1] = 1;
    a[2] = 2;
    System.out.println(arr);
}

루프는 대체로 많은 시간을 사용한다. 즉, 반복되는 루프의 횟수를 줄일 수 있으면 그 만큼 실행 실행 속도가 빨라지게 된다. 하지만 반복 횟수가 많은 경우엔 사용할 수 없다.

공통 하위 표현식 제거

public static void main(String[] args) {
    a = b * c + g;
    d = b * c * e;
    
    // 아래와 같이 변경
    tmp = b * c;
    a = tmp + g;
	d = tmp * e;
}

공통 코드를 중복 실행하지 않고 한번 실행한 값을 이용하여 최적화하는 방법.

로컬 변수 레지스터 할당

로컬 변수를 레지스터에 할당하여 사용하여 메모리까지 가는 수고를 줄여서 속도를 높임.

String 연산

 public static void main(String[] args) {
	String[] strs = {"a", "b", "c"};
	String str = "";
	for (int i = 0; i < strs.length; ++i) { //for 문 사용
		str += strs[i];
	}
	System.out.println(str);

	String str2 = strs[0] + strs[1] + strs[2]; // 일반 연산
	System.out.println(str2);

	String str3 = "S" + "t" + "r"; // String str3 = "Str";
	System.out.println(str3);
}

String을 연산 할 땐, JDK1.5 이전에는 String객체를 생성해서 새로 할당 하는 방식으로 비효율적 이었다.

JDK1.5부터 Stringbuilder를 사용하여 컴파일 되었고, JDK9부턴 StringConcatFactory객체를 사용하여 String 연산을 컴파일 한다.

직접 확인 하는 방법은 bytecode를 보면 되는데 Intellij에는 한 번 실행 후 Shift두번 눌러 show bytecode를 입력하면 볼 수 있다.

주의사항

최적화를 지나치게 수행하면 의도하지 않은 동작이나 버그가 발생할 수 있으므로 주의가 필요하다.


한 줄평 : 자바에서는 javac 보단 JIT compiler에서 더 많은 최적화를 수행한다.

참고 -
https://www.epnc.co.kr/news/articleView.html?idxno=48128
https://jerry92k.tistory.com/50

profile
no-intelli 개발자 입니다. 그래도 intellij는 씁니다.

0개의 댓글