내가 만든 프로그램의 속도를 알고 싶다

시스템의 성능이 느릴 때 가장 먼저 해야 하는 작업은 병목 지점을 파악하는 것이다.

System 클래스

모든 System 클래스의 메서드는 static으로 되어 있고, 그 안에서 생성된 in, out, err와 같은 객체들도 static으로 선언되어 있으며, 생성자도 없다(private으로 되어 있음).

System 클래스에서 자주 사용하지는 않지만 알아두면 매우 유용한 메서드에는 어떤 것들이 있는지 알아보자.

static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
String[] arr = new String[]{"AAA", "BBB", "CCC", "DDD", "EEE"};

String[] copiedArr = new String[3];
System.arraycopy(arr,2,copiedArr, 1, 2);

결과 : null CCC DDD

예를 들어 위와 같이 arraycopy 메서드를 사용했다면, arr 배열의 2번 인덱스부터 copiedArr 배열의 1번 인덱스 위치에 2개 복사하겠다는 뜻이다.

자바의 JVM에서 사용할 수 있는 설정은 크게 두가지로 나뉜다. 하나는 속성(Property)값이고, 다른 하나는 환경(Environment)값이다. 속성은 JVM에서 지정된 값들이고, 환경은 장비(서버)에 지정되어 있는 값들이다. 자바에서는 영어 단어 그대로 "속성"은 Properties로, "환경"은 env로 사용한다. 먼저 Properties를 사용하는 메서드에 대해서 알아보자.

// 현재 자바 속성 값들을 받아 온다.
static Properties getProperties()

// key에 지정된 자바 속성 값을 받아 온다.
static String getProperty(String key)

// key에 지정된 자바 속성 값을 받아온다. def는 해당 key가 존재하지 않을 경우 지정할 기본값이다.
static String getProperty(String key, String def)

// props 객체에 담겨 있는 내용을 자바 속성에 지정한다.
static void setProperties(Properties props)

// 자바 속성에 있는 지정된 key의 값을 value 값으로 변환한다.
static void setProperty(String key, String value)

이러한 자바 속성 관련 메서드를 어떻게 사용하는지 다음의 예를 통해 알아보자.

public class GetProperties {
    public static void main(String args[]) {
        System.setProperty("JavaTuning", "Tune Lee");
        Properties prop = System.getProperties();
        Set key = prop.keySet();
        Iterator it = key.iterator();

        while(it.hasNext()) {
            String curKey = it.next().toString();
            System.out.format("%s=%s \n", curKey, prop.getProperty(curKey));
        }
    }
}

이 소스는 'Java Tuning'이라는 키를 갖는 시스템 속성에 'Tune Lee'라는 값을 지정한 후, 시스템 속성 전체 값을 화면에 출력해 주는 프로그램이다. 이 프로그램을 수행하면 수십 개의 자바 시스템 속성값을 출력한다. 그 결과 중 우리가 지정한 'Java Tuning' 키를 갖고 'Tune Lee' 값을 가지는 속성이 추가되어 출력될 것이다.

// 현재 시스템 환경 값 목록을 String 형태의 맵으로 리턴한다.
static Map<String, String> getenv()

// name에 지정된 환경 변수 값을 얻는다.
static String getenv(String name)
public class GetEnv {
    public static void main(String args[]) {
        Map<String, String> envMap = System.getenv();
        Set key = envMap.keySet();
        Iterator it = key.iterator();

        while(it.hasNext()) {
            String curKey = it.next().toString();
            System.out.format("%s=%s \n", curKey, envMap.get(curKey));
        }
    }
}

그리고 운영중인 코드에 절대로 사용해서는 안되는 메서드가 있다.

// 자바에서 사용하는 메모리를 명시적으로 해제하도록 GC를 수행하는 메서드다.
static void gc()

// 현재 수행중인 자바 VM을 멈춘다. 
static void exit(int status)

// Object 객체에 있는 finalize()라는 메서드가 자동으로 호출되는데, GC가 알아서 해당 객체를 더 이상 참조할 필요가 없을 때 호출한다.
// 하지만 이 메서드를 호출하면 참조 해제 작업을 기다리는 모든 객체의 finalize() 메서드를 수동으로 수행해야 한다.
static void runFinalization()

다시 이야기하지만, 이 세 개의 메서드들은 절대 사용하면 안된다.

System.currentTimeMillis와 System.nanoTime

이제 시간 관련 메서드에 대해서 본격적으로 알아보자.

// 현재의 시간을 ms로 리턴한다(1/1,000초)
static long currentTimeMillis()

currentTimeMillis() 메서드에서 리턴해 주는 결과 값은 ms(밀리초)다. UTC라는 시간 표준 체계를 따르는데, 1970년 1월 1일부터의 시간을 long타입으로 리턴해 준다. 따라서 호출할 때마다 다르다.

20 ms 0.02초
1,200 ms 1.2초
6,000,000 ms 6,000초
// 현재의 시간을 ns로 리턴한다(1/1,000,000,000초)
static long nanoTime()

nanoTime() 메서드는 JDK 5.0부터 추가된 메서드다. 되도록이면 nanoTime() 메서드의 결과로 판단하도록 하자.

cf) JMH에 대한 내용은 'story04 어디에 담아야 하는지'에서 정리함

Last updated