해당 포스트는 "자바 성능 튜닝 이야기" 책의 내용을 요약한 것이다.



해당 포스트를 읽기 전에 static에 대한 기본적인 지식이 있어야 한다. 기본 지식이 없다면 "왜 main() 메서드는 static인가?" 포스트를 읽길 바란다.


※ Static

: static은 gc의 대상이 되지 않는다. 따라서 static을 잘 사용하면 성능을 뛰어나게 향상시킬 수 있다. 하지만 잘못 사용할 경우 예상치 못한 결과를 초래한다. 특히 웹 환경에서 static을 잘못 사용하다가 여러 쓰레드에서 하나의 변수에 접근할 수 있기 때문에 데이터가 꼬이는 큰 일이 발생할 수 있다.


- 자주 사용하고 절대 변하지 않는 변수는 final static으로 선언해라. 예로 단순한 쿼리 문장을 final static으로 사용하면 적어도 1byte 이상의 객체가 GC 대상에 포함되지 않는다.


- 설정 파일 정볻 static으로 관리해라. 클래스의 객체를 생성할 때마다 설정 파일을 로딩하면 엄청난 성능 저하가 발생한다. 따라서 반드시 static으로 데이터를 읽어서 관리해야 한다.


ex)

public class QueryManager{
    private static String query = null;
    public QueryManager(String query){
            this.query = query;
    }
    public static String getSql(String idSql){
        try{
             FileReader reader = new FileReader();
             HashMap<String, String> document = reader.read(query);
             return document.get(idSql);
       }catch(Exception e){}
       return null;
    }
}

위 코드의 경우 개발자가 본인의 pc에서 테스트할 때는 전혀 문제가 되지 않는다. 하지만 다수의 사용자가 접근할 시 문제가 된다. 특정 사용자가 어떤 화면에 접근할 때 특정 쿼리문으로 static 변수인 query가 초기화 됐고 getSql 메서드에 접근한다고 해보자. 그러던 중에 다른 사용자가 다른 화면에 접근에 다른 쿼리문이 query 변수에 저장됐다. 그러면 처음 사용자는 query 변수가 static이기 때문에 다른 데이터를 가지는 query 변수에 접근하게 되고 원치 않는 결과를 얻게 된다. 즉, 모든 스레드에서 동일한 주소를 가리키는 변수에 접근하게 되어 문제가 발생한 것이다. 또 다른 예를 보자.

private static boolean successFlag;

위 successFlag 변수는 응시자의 합격 여부를 저장한다. 위 코드 또한, 개발자 본인의 pc에서 테스트할 때는 문제가 발생하지 않는다. 하지만 다수의 사용자가 사용할 시 문제를 일으킨다. 특정 응시자가 시험에 합격에서 successFlag가 true 값으로 저장됬다고 하자. 그리고 합격 결과를 보여주기 전에 시험에 불합격한 응시자가 접근해서 successFlag 변수가 false로 저장됬다. successFlag 변수는 static이기 때문에 합격한 응시자는 false 값을 가진 불합격 결과를 보게 된다. 


- 메모리 릭

: static으로 선언한 부분은 GC가 되지 않는다. 만약에 Collection 객체를 static으로 선언하고 지속적으로 해당 객체에 데이터가 쌓인다면 어떻게 될까? 결국에는 GC가 되지 않아 시스템은 OutOfMemoryError을 발생시킨다. 즉, 시스템을 재시작해야 하는 상황에 오게 된다. 이렇게 더 이상 사용 가능한 메모리가 없어지는 현상을 메모리 릭이라고 한다. 따라서 static 변수를 사용할 때 메모리를 고려해야 한다.




+ Recent posts