레이블이 SW development인 게시물을 표시합니다. 모든 게시물 표시
레이블이 SW development인 게시물을 표시합니다. 모든 게시물 표시

2010년 12월 9일 목요일

Eclipse 사용시 Static import가 자동으로 되도록 하기 - 방법 두번째

최근에 Favorite를 이용하는 방법을 소개하였다.

오늘 다른 방법을 제시하는 글을 보았다.

테스트 코드에서 static import를 편하게 넣는 방법

테스트 코드 작성을 위해서 Favorites 기능을 추천해주는 사람을 보면 과연 테스트 코드를 제대로 작성하고 있는 사람인지 의심부터 간다.
이렇게 개인적으로 유괘하지 않은 부분도 있다.

나와는 코드를 짜는 습관이 다른것 같다. 나는 코드를 짤때 코드 어시스트(ctrl - space)를 무척이나 많이 사용한다. 보통 한두자 치고는 누르는게 습관인 것 같다. 그래서 편했는데 아닌 사람도 있구나 하는 생각이 들었다.

인용한 방법대로 하는 것도 좋은 방법이라고 생각된다. 특히 많은 static import를 사용할 경우에는 매우 효과적이다.

다만 모든 Static class의 함수를 한번이라도 이용하지 않는 경우 저장은 하지 말아야 한다. 저장과 동시에 Organize Import가 작동하면서 사라지기 때문이다. 이 부분을 설정할 수 있는 다른 방법도 있을 것이다.

하지만 나는 favorites를 이용하는 것이 더 좋은 방법이라는 생각이 든다.

Powered by 쓰리래빗츠






2010년 12월 7일 화요일

Better for Loops Pattern in javascript

javascript에서 for Loops를 사용할 경우에 이제껏 다음과 같이 사용했다.

for(var i = 0; i < myArray.length; i++) {
    do something with myArray[i];
}


JavaScript Patterns 에서는 이런 방식의 사용이 성능에 아주 좋지 않은 영향을 미친다고 한다.
특히 DOM과 관련된 array를 다루는 경우에는 특히 그 영향이 크다고 할 수 있다.

document.getElementsByName()
document.getElementsByClassName()
document.getElementsByTagName()

이런방식으로 반환되는 Array의 경우이다. 이런경우에는 다음과 같이 사용하는 것이 좋다.

var i = 0,
     max,
     myarray = [];
// ...
for (i = 0, max = myarray.length; i < max; i++) {
    // do something with myarray[i]
}

이럴 경우 Safari3 브라우저에서는 2배, IE7에서는 190배 빠르다고 한다.
이유는 length를 가져오는 로직이 시간이 걸리기 때문이다.

참고로 성능이 매우 중요한 프로그램에서는 다음과 같이 성능 향상도 가능하다.

var i, myarray = [];
for (i = myarray.length; i--;) {
    // do something with myarray[i]
}

또는

var myarray = [],
      i = myarray.length;
while (i--) {
    // do something with myarray[i]
}

Prototype 이나 JQuery 같은 Javascrip 라이브러리의 DOM 관련 fuction의 경우에는 어떤지 잘 모르겠다.



2010년 12월 2일 목요일

Eclipse 사용시 Static import가 자동으로 되도록 하기

JAVA 1.5 버전에서 소개된 static import는 사용여부를 두고 찬반이 갈린다. 하지만 다른 경우는 별도로 하고서라도 Junit에서 assert Mehod 시리즈들을 사용할때에는 편리하다고 판단된다.

Eclipse로 작업하다 보면 최초에 static import를 수동으로 해야 되는 경우가 많다.
이 경우 환경설정 값을 조금만 수정하면 method를 타입핑시에 assert method를 code assist 기능을 이용하여 선택할 수 있고 선택됨과 동시에 static import 구문도 동시에 삽입된다.


위와 같이 Java > Editor > Favorites 에 New Type으로 사용하고자 하는 static Class를 추가하고(Junit인 경우에는 org.junit.Assert) 저장하면 Java 코딩시 "ass" 만 치면 Assert class의 method들이 아래 그림과 같이 나타나고 선택하면 자동으로 static import가 된다.


모든 Static Class를 대상으로 된다.

2010년 11월 30일 화요일

Eclipse Helios (3.6) Update 후기

Eclipse Galileo (3.5)를 사용하다가 Eclipse Helios (3.6)로 업데이트를 했다.

결론부터 말하면 호완성과 관련하여 발견된 문제는 없다.
기존에 사용하던 workspace와도 아무런 문제가 없다.

Workbench User Guide, Java development user guide의 What's news  부분만 살펴보니
많은 개선이 된거같다.

기존 버전의 완성도도 매우 높은 편이라 당장 느껴지는 점은 없다.

다만 개인적으로 기존의 몇가지 아쉬운 점이 해결되어 만족한다.

XP인 경우 발생하는 Eclipse start Error 가 해결되어 별도의 처리가 줄어 들었다는 점이 만족스럽고,

java 스크립트에서 "{}" 자동완성이 된다는 점은 더욱더 만족스럽니다.
JavaScript Development Toolkit (JSDT) 플러그인이 업데이트 되면서 해결된 것으로 생각된다.

2010년 6월 13일 일요일

Database에 긴 Text를 입력하는 다양한 방법

Database에 Text를 저장할때 가장 많이 사용하는 방식은 VACHAR(N) - DB가 Oracle인 경우에는 VACHAR2(N)을 사용하는 방식이다.

DB마다 조금씩 다르기는 하지만 VACHAR 또는 VACHAR2의 길이는 4,000 character로 제한된다. (특이하게 Derby의 경우에는 32,672 characters이다)

그래서 많이 쓰는 방식이 CLOB 또는 LONG VACHAR 이다. 그런데 2가지의 경우의 특징은 다음과 같다.

CLOB TYPE 사용
  • 데이터의 제한이 거의 없다(일반적으로 2 Gigabytes 까지 지원한다.)
  • 지원하지 않는 DB의 경우에도 다른 Type으로 지원한다.( 예를 들면 TEXT가 대표적이다.)
  • JAVA에서 사용하기 위해서는 java.lang.String이 아닌 java.sql.Clob Class를 이용하여야 한다.

LONG VACHAR 사용
  • 가장 많이 쓰는 상용 DB인 Oracle 에서 LONG TYPE으로 지원하다가 최시버전에서 Depreciated 되었다.(VACHAR가 Depreciated 되고 VACHAR2 사용을 유도하는 이유와 동일한 이유에서 진행되었다.)
  • DB별로 데이터 제한이 다르다.(일반적으로 2 Gigabytes이나 Derby의 경우 32,700 characters 이다)
  • JAVA에서 사용하기 위해서 java.lang.String Class를 사용하면 되기 때문에 편하다.

많은 DB를 지원하기 위해서는 CLOB을 사용하는 것이 가장 편한 방법으로 판단되지만 CLOB을 자바에서 사용하기 위해서는 java.lang.String으로 변경하는 별도의 방법이 필요하다.( java.sql.Clob 의 경우 긴 데이터이기 때문에 당연한 방법이기는 하지만 Reder를 이용하여 데이터를 읽어오는 방식이기 때문에 짧은 데이터의 경우 java.lang.String을 사용하는 것보다 번거럽다.) 만약 30,000 내외의 CARACTER를 이용하는 경우라면 LONG VACHAR(Oracel의 경우 LONG을 사용하는 것 - Depreciated 되었다는 점이 찜찜하긴 하지만 ORACLE의 최신버전에서도 완전히 제거하기는 힘들것으로 판단된다.)도 괜찮은 대안으로 생각된다.

추가로 이제껏 Oracle을 사용하면서 VACHAR2를 많이 사용했는데 이 TYPE의 경우 ANSI-SQL에서 지원하는 TYPE은 아니라는 사실을 알게 되었다. 그리고 Oracle 에서는 VARCHAR TYPE이 Depreciated 되었다는 사실도 새롭게 알게되었다.


2010년 3월 14일 일요일

jad로 package로 된 class 파일 Decompile 하기

도움말을 보아도 잘 알수가 없어서 간략하게 정리한다.

 

  • Package를 Decompile 할 경우 사용 방식
Jad -o -r -s.java -ff -nonlb **/*.class

2010년 2월 1일 월요일

java.util.jar 또는 java.util.zip package 사용시 한글 인코딩 문제

Java로 파일을 압축하는 경우 가장 많이 쓰이는 방법은 java.util.jar 또는 java.util.zip 라고 생각된다. java.util.jar package 역시 java.util.zip package 를 상속 받은 것이니 결국 둘은 같은 로직을 사용한다.

 

이 두 package는 내부적으로 UTF-8 encoding을 사용한다. 그래서 해당 package를 사용하는 경우에는 UTF-8을 사용하지 않은 압축 프로그램(경험한 바로는 빵집)에서는 한글이 깨지는 문제가 발생한다. 해당 버그는 4244499 버그로 몇년동안 Top 25 Java Bugs 에서 1등을 한 전적을 가지고 있었다고 한다.

 

현재의 JDK 최신버전에서도 encoding 타입을 지정해 줄수는 없기 때문에 해결은 책은 없다. 다만 OpenJDK 7을 사용하면 encoding을 지정할 수 있다고 한다. 추후 JDK에서는 수정될 가능성이 많다고 할 수 있다.

 

java.util.jar 또는 java.util.zip package 사용하여 압축을 하고 테스트를 위해 PC에서 압축 프로그램을 이용하여 파일을 연 다음 한글이 깨진다면 위에서 말한 버그일 가능성이 많다.

 

PS) 빵집을 언급하기는 했지만 빵집의 문제는 아니다. Java의 문제이다. 빵집은 개인적으로 아주 고맙게 잘 사용하고 있는 프로그램 중에 하나이다.

2010년 1월 26일 화요일

[펌] Thread Safe Singleton 구현법 - 제 2탄

 

소스코드내에는 몇가지 싱글톤 구현방법이 나옵니다. 그 각각이 의미하는바는 다음과 같습니다.

 

1) EagerSingleton


  static class EagerSingleton extends Singleton {
    static final EagerSingleton theInstance = new EagerSingleton();
    static EagerSingleton getInstance() {
      return theInstance;
    }
  }

 

이 경우는 미리 싱글톤 인스턴스를 생성하는 방법으로 static final 필드에
인스턴스를 생성하여 할당하는 방법입니다. 이 필드는 클래스로더에 의해서
EagerSingleton이 메모리로 올라오는 순간에 안전하게(thread-safe하게)초기화
됩니다. 이 방법이 아마 성능이 가장 우수하게 나타날 것입니다.

장점은 동기화부담이 적다는 것입니다. 단 한번 클래스로더가 thread-safe하게
클래스를 로드하는 시점에 클래스가 로딩되어 안전합니다. 단점은 인스턴스가
미리부터 생성된다는 것입니다.

 

2) SynchedSingleton


  static class SynchedSingleton extends Singleton {
    static SynchedSingleton theInstance;
    static synchronized SynchedSingleton getInstance() {
      if (theInstance == null)
        theInstance = new SynchedSingleton();
      return theInstance;
    }
  }

 

이 방법은 싱글톤 필드에 접근할때마다 동기화를 수행하는 방법입니다. 매번
동기화를 수행하므로 자바 메모리 모델에 따른 각종 문제를 방지할 수 있어
thread-safe합니다. 단점은 매번동기화를 수행하므로 수행 비용이 높다는
것입니다.

 

3) ThreadLocalSingleton


static class ThreadLocalSingleton extends Singleton {
    static final ThreadLocal perThreadInstance = new ThreadLocal();
    static final Object lock = new Object();
    static ThreadLocalSingleton theInstance;

    static ThreadLocalSingleton getInstance() {
      ThreadLocalSingleton instance = (ThreadLocalSingleton)(perThreadInstance.get());
      if (instance == null) {

        synchronized(lock) {
          instance = theInstance;
          if (instance == null)
            instance = theInstance = new ThreadLocalSingleton();
        }
        // copy global to per-thread
        perThreadInstance.set(instance);
      }
      return instance;
    }
  }


 

 

이 방법은 Thread Local Storage를 사용한 해법입니다. 자바 쓰레드 메모리 모델에서
문제가 발생하는 것은 멀티 CPU상황에서 각각의 CPU가 자신의 캐시내에 클래스의
필드를 복사해넣는다는 것입니다. 이러한 캐시는 메인메모리와 동기화가 되어
있지 않습니다. 즉, 각각의 CPU가 하나의 클래스를 접근하게되면 각각의 CPU는
그 클래스의 내용을 다르게 볼 수 있다는 것입니다. 싱글톤을 구현하면 instance라는
필드를 여러개의 CPU가 참조하는데 이 필드를 여러개의 CPU가 다르게 보게 됩니다.
예를들어 CPU A가 인스턴스를 생성하고 생성한 인스턴스를 instance에 할당한다고
합시다. 그러면 CPU A가 또다시 이 instance 필드를 참조할때는 생성된 인스턴스를
제대로 보게 됩니다. 그러나 CPU B가 이 instance필드를 참조할때는 instance필드가
null로 나타날 수 있습니다. 그 이유는 CPU A가 수행한 작업은 synchronized블록을
통과할때까지 메인메모리에 반영이 안되고 자신의 캐시내에만 담겨 있을 수 있으며,
CPU B역시 synchornized블록을 통과하지 않으면 메인메모리가 아닌 자신의 캐시만
들여다보기 때문입니다.

이를 해결하려면 각각 CPU가 동기화블록을 들어갔다가 나와야만 하는데,
이를 구현한 것이 위의 코드입니다. 각각의 Thread는 자신만의 메모리공간으로서
TLS(Thread Local Storage)를 가지고 있으며 이들은 매 쓰레드마다의 공간이므로
동기화될 필요가 없습니다. 따라서 이 저장소에 해당 쓰레드가 synchronized블록을
한번이라도 다녀왔는지(한번이라도 다녀오면 CPU가 메인메모리의 값을 가져오니까요)를
저장해둡니다.

 

4) SimulatedThreadLocalSingleton


  static class SimulatedThreadLocalSingleton extends Singleton {
    static SimulatedThreadLocalSingleton theInstance;
    static final Object lock = new Object();
    static final Object key = new Object();

    static Singleton getInstance() {
      TSS t = (TSS)(Thread.currentThread());
      Singleton instance = (Singleton)(t.threadLocalHashtable.get(key));
      if (instance == null) {

        synchronized(lock) {
          instance = theInstance;
          if (instance == null)
            instance = theInstance = new SimulatedThreadLocalSingleton();
        }
        // copy global to per-thread
        t.threadLocalHashtable.put(key, instance);
      }
      return instance;
    }
  }

 

이 방법은 TLS를 ThreadLocal 클래스를 쓰지 않고 직접구현한 방식입니다.

 

5) VolatileSingleton


static class VolatileSingleton extends Singleton {
    static final Object lock = new Object();
    static volatile VolatileSingleton theInstance;

    static VolatileSingleton getInstance() {
      VolatileSingleton instance = theInstance;
      if (instance == null) {
        synchronized(lock) {
          instance = theInstance;
          if (instance == null)
            instance = theInstance = new VolatileSingleton();
        }
      }
      return instance;
    }
  }


  

주의!)이 방법은 절대로 사용해서는 안됩니다.

이 방법은 volatile를 사용합니다. volatile 로 선언된 필드는 매번 원자적으로
쓰레드 safe하게 이루어집니다. 즉 각각의 변수에 대한 접근이 매번 메인메모리와
동기화될 뿐만아니라, thread safe하게 이루어집니다. synchronized와 volatile은
이처럼 변수의 접근마다 동기화를 하느냐 아니면 특정 블록을 통채로 동기화
하는냐의 문제에 있어서 접근방법이 틀립니다. 그러나 아쉽게도 volatile은
대부분의 자바 컴파일러에서 제대로 구현되어있지않으며 따라서 사용하는것을
권하지 않습니다. SUN의 컴파일러는 제대로 되지 않느냐 하고 생각하실 수 있지만
전혀 안그렇습니다. SUN의 JDK 1.3대에서도 제대로 구현이 되어있지 않습니다.
volatile은 동기화의 문제를 비롯한 다양한 암시적 작동이 보장되어야하는데
이를 제대로 책임지고 않기때문입니다.

 

6) DirectThreadFieldSingleton


  static class DirectThreadFieldSingleton extends Singleton {
    static DirectThreadFieldSingleton theInstance;
    static final Object lock = new Object();

    static Singleton getInstance(TSS t) {
      Singleton instance = t.singleton;
      if (instance == null) {

        synchronized(lock) {
          instance = theInstance;
          if (instance == null)
            instance = theInstance = new DirectThreadFieldSingleton();
        }
        // copy global to per-thread
        t.singleton = instance;
      }
      return instance;
    }
  }


 

인스턴스를 할당받고자하는 쪽에서 TSS라는 형태의 클래스를 쓰레드마다 할당한채로
갖고 있다가 이것을 싱글톤 클래스에 넘깁니다. 그러면 TSS.singleton변수의
값을가지고 동기화 수행여부를 결정하는 방식입니다. ThreadLocal의 변형이며,
모든 인스턴스를 획득하고자하는 쓰레드가 TSS를 넘겨야한다는 점에서
좋은 방법은 아니겠죠.

 

7) ThreadFieldSingleton


  static class ThreadFieldSingleton extends Singleton {
    static final Object lock = new Object();
    static ThreadFieldSingleton theInstance;

    static Singleton getInstance() {
      TSS t = (TSS)(Thread.currentThread());
      Singleton instance = t.singleton;
      if (instance == null) {

        synchronized(lock) {
          instance = theInstance;
          if (instance == null)
            instance = theInstance = new ThreadFieldSingleton();
        }
        // copy global to per-thread
        t.singleton = instance;
      }
      return instance;
    }
  }


 

이 방법역시 ThreadLocal의 구현에 대한 변형된 구현입니다. ThreadLocal 대신,
특정 싱글톤 클래스에 대한 인스턴스를 획득하려고 시도하는 쓰레드를 캐스팅해서
ThreadLocal을 구현한 것이죠. 개인적으로 이 방법은 별로 좋지 않다고봅니다.
특정 클래스의 인스턴스를 획득하려면 쓰레드가 어떠한 인스턴스를 구현하고
있는지는 쉽사리 가정하기가 곤란하죠.

2009년 12월 28일 월요일

Generic 정보를 Reflection으로 알아내기

최근에 JDK1.5로 개발을 할 기회가 생겼다. 근무하던 사이트의 JDK 버전이 1.4 였기 때문에 처음 접하는 JDK 1.5  버전은 무척이나 생소했다.

 

1.5에서 새로 도입된 기술로 Generic, Annotation, Enum 정도가 대표적이라고 생각한다. 그리고 이 기술은 첨 볼때 무척이나 생소하게 느껴졌다. 현재는 이러한 기술들로 개발을 진행하면서 참 편하다고 생각이 든다. java.sun.com 의 튜토리얼보다 더 잘 정리할 자신은 없지만 각각의 주제에 대하여 간단한 글을 써야 되겠다는 계획을 현재 가지고 있다.

 

일단 글을 읽으시는 분들이 Generic에 대하여 익숙하하다고 가정하고, 요 몇일간 내가한 시간낭비의 결과를 간략하게 적으려고한다.

 

한마디로 요약하면 Generic 정보를 Reflection을 이용하여 Run-time에 알아낼 수 있는 방법이 있을까 하는 점이다.

 

List <String> srtList = new ArrayList<String>();

 

위의 형태로 정의된 필드에서 "String"을 알아낼 수 있는 방법이 없을까 하는 것이 고민이었다.

 

결론도 한마디로 정의 하면 "안된다"이다. 부끄럽게도 Generic 튜토리얼에 Type Erasure 라는 개념으로 설명이 되어 있었다. 말은 어렵지만 결국 Generic을 지원하는 Java 버전과 지원하지 않는 Java Version의 호환을 위하여 컴파일할때 Generic 정보는 모두 지운다는 의미이다. 지워진 정보를 Run-time에서 찾으려고 시도를 하니 안되는 것이 당연하다. 하지만 우리에게는 Annotation이 있다. 그래서 최종적으로 해결한 소스는 다음과 같다.

 

@SampleAnnotation( class = "java.lang.String")

List <String> srtList = new ArrayList<String>();

 

이렇게 정의하고 Annotation을 다음과 같이 정의 하면 원하는 로직을 구현 할 수 있다.

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SampleAnnotation{
 String class();
}

 

 

2009년 12월 5일 토요일

Primary Key 생성 전략 또는 방법

관계형 데이터베이스를 사용하는 환경에서는 Primary Key를 관리하는 방법이 필요하다. 특히 Multi - Thread 환경에서는 특별한 방법을 적용하지 않는다면 Primary Key Collision(충돌)을 피할 수 없다.

1. Select Max(XXX) + 1 을 Insert 시에 사용하는 방법

INSERT INTO TABLE (ID)
            VALUES (SELECT MAX(ID) + 1 FROM TABLE)

이 방법의 장점은 소스코드에서 아무런 작업을 해 줄 필요가 없다는 것이다. 그러나 단점은 현재의 추세인 OR - Mapping을 하는 환경에서는 사용할 수 없다는 점이다. DB에 저장하기 전까지 ID 값을 알수 없으며 저장한 후에도 ID 값을 알기위해서는 다시 조회하는 별도의 과정이 필요하다. 결국 Class에서 ID 값을 확인할 필요가 전혀 없는 경우에만 사용이 가능하다.

2. DB에서는 제공하는 기능을 사용하는 경우
DB에서 일련번호를 제공하는 기능을 사용하는 방법이다. IDENTITY column type을 제공하는 DB 또는 SEQUENCE 기능을 제공하는 DB를 사용할 경우에는 위에서 제공하는 기능을 이용해서 구현하면 된다. 구현 방법은 각 DB마다 조금씩 다르기는 하지만 SQL을 이용하는 간단한 방법이다.

이 방법의 장점은 생성로직을 소프트웨어 개발자가 별도로 구현할 필요가 없다는 점이다. 그러나 모든 DB가 제공하는 기능은 아니며 제공하는 방식도 약간씩은 상이해서 모든 DB를 지원해야 하는 OR Mapping Tool에는 적용하기 힘들다.

3. 테이블을 이용하는 방법
별도의 테이블을 이용하여 관리하는 방식이다. 아래와 같은 테이블을 만든 후에 Primary Key 생성로직을 별도로 구현하는 방식이다.

CREATE TABLE ID_GEN(GEN_KEY VARCHAR(10) NOT NULL,
                   GEN_VALUE INTEGER NOT NULL,
                   primary key (GEN_KEY));

이 방법의 장점은 모든 DB에 대하여 구현할 수 있다는 점이다. 단점은 위의 방법보다는 좀 복잡한 로직으로 구현을 해야 한다는 단점이 있다.

4. UUID를 이용하는 방법
 Primary에 UUID를 이용하는 방법이다. 가장 간단한 방법이다. 단점은 데이터베이스 용량을 많이 차지 한다는 문제가 있다. 그리고 위의 방법들과 다른 장점은 멀티사이트(여러 DB를 각각 사용하면서 데이터의 Primary Key는 달라야 하는 사이트)에서도 적용이 가능하다는 점이다.

2009년 12월 4일 금요일

Eclipse start Error 해결하기 (JVM terminated. Exit code=-1)


개발을 진행하던 모듈의 JDK 버전을 1.5 에서 1.6으로 업그레이드 하기로 결정했다. 설치한 소프트웨어는 다음과 같다.

OS : Window 7 홈 프리미엄
JDK : jdk-6u17-windows-i586.exe
Eclipse : eclipse-jee-galileo-SR1-win32.zip

회사에서 사용하는 노트북은 Window7이기 때문인지 JDK 1.6(jdk-6u17-windows-i586.exe)을 설치하고 eclpe(eclipse-jee-galileo-SR1-win32.zip)를 설치하니 아무런 문제 없이 개발환경이 잘 세팅되었다.

그런데 문제는 집에서 같은 환경을 설치하려고 할때 발생하였다. 사무실과 다른 점은 OS가 Window XP 라는 점 뿐인데 실행이 정상적으로 되지 않았다. 실행시에 다음과 같은 에러 메세지가 나타난다.


















"JVM terminated. Exit code=-1" 키워드로 검색을 해보니 Eclipse Start Error 라고 해서 많은 해결책들이 제시되고 있다. 각 해결책들의 장단점과 몇가지 추가적인 정보를 정리하면 다음과 같다.

1. eclipse.exe 바로가기를 만든후에 -vm 파라미터를 이용하여 어떤 JVM을 사용할지 정해주는 방법
  바로가기 속성에 아래와 같이 설정하고 실행시키면 된다.

  C:\eclipse\eclipse.exe -vm "C:\Program Files\Java\jdk1.6.0_17\jre\bin\javaw" 
제일 간단한 방법이기는 하지만 JDK를 바꿀경우 항상 변경해야 하고 실행시에는 만들어진 단축키만을 이용해야 한다는 단점이 있다. 그래서 Eclipse를 실행시킬 경우 JVM 파라미터를 별도로 관리하는 eclipse.ini를 이용하는 방법도 있다. 그리고 이 방법은 모두 바로가기의 속성에 파라미터를 변경시키는 방법과 동일하다. 결국 eclipse.ini가 바로가기에 파라미터를 추가하는 것을 모아 놓은 것이라고 생각하면 된다.

2. launcher.XXMaxPermSize 관련 정보를 수정하는 방법
eclipse.ini 의 내용중에 launcher.XXMaxPermSize 관련된 정보를 삭제하는 방법이다.
삭제대상인 부분은 다음과 같다.

--launcher.XXMaxPermSize
256M

아주 간단한 방법이기는 하지만 수정하는 파라미터의 의미가 이클립스가 사용하는 메모리를 제한하는 것이기 때문에 이렇게 해 놓고 이클립스에서 많은 작업을 할경우 시스템이 죽는 경우가 있어서 사용하기 좋지 않은 방법이다.
3. Xmx512m 을 수정하는 방법
JVM의 최대 메모리를 설정하는 Xmx512m 파라미터를 수정하여도 문제는 해결된다.

Xmx256m

이것도 간단한 방법이기는 하지만 기껏 개발 PC의 메모리를 4GB로 용량을 늘려놓고 JVM에서는 512도 사용하지 못하기 때문에 추천하고 싶은 해결방안은 아니다.
4. 사용해야할 VM을 명시적으로 적용
1번 방법인 바로가기의 속성을 고치지 않고 같은 방식으로 VM을 지정해 주는 방법이다. clipse.ini 설명 문서의 Specifying the JVM  를 참고하여 아래과 같이 지정해 주면된다.

-vm
C:\Program Files\Java\jdk1.6.0_17\jre\bin\javaw

주의할점은 항상 -vmargs 설정보다 위에 위치하여한다. -vmargs 설정보다 아래에 있는 설정은 무시되기 때문이다.
가장 추천하고 싶은 방법은 4번이다. 하지만 각 상황에 맞게 알맞은 방법을 사용하면 된다.

문제가 발생하는 정확한 원인을 알고 싶어서 꽤 오랜 시간 정보를 검색해 보았으나 명확한 원인은 발견되지 않고 있다. 참고로 JDK1.5를 사용하는 경우도 마찬가지의 오류가 발생한다. 모든 환경에서 발생하는 것은 아닌 것으로 판단되나 정확히 어떤 원인인지도 잘 모르겠다. 혹시 아시는 사람이 있다면 의견이나 트랙백을 부탁한다.

2009년 12월 1일 화요일

java.util.logging 사용법 및 설정방법

개발을 진행하다가 로그를 남길때 사용할 수 있는 가장 간단한 방법은 java.util.logging을 사용하는 것이다. 사용법은 매우 간단하다.


로그를 사용하는 자세한 사용법은 Java Logging Overview이 자세히 설명하고 있다. 해당 문서를 번역하고 싶은 생각은 없다. 하지만 설정방법에 대하여 간단하게 Tip&Tech가 있어서 설명하려고 한다.

로그의 설정은 일반적으로 WAS에서 설정하여 사용할 것이다. 그런데 현재 개발을 모듈별로 하기 때문에 eclipse에서 위와 같은 코드를 작성하고 테스트를 진행하면 info 보다 낮은 레벨의 로그를 Console에 출력되지 않는다. 그렇게 되는 이유는 ConsoleHandler 의 기본 레벨이 Info이기 때문이다. 그러면 이 설정을 바꾸기 위해서는 설정을 바꾸어야 한다. 설정파일은 특별한 작업을 하지 않았다면( JVM 실행시 다음 파라미터 "java.util.logging.config.class" "java.util.logging.config.file" 를 추가하지 않았다면) 프로그램이 실행되는 JRE 디렉토리의 "lib/logging.properties"이다.

먼저 다음과 같이 설정을 변경한다.

java.util.logging.ConsoleHandler.level = FINEST

그런데 수정한 후에도 아무런 로그가 남지 않는다. 왜일까? 로그는 패키지명별로 로그레벨을 보유하고 있기 때문에 각 패키지의 로그레벨도 변경하여야 하기 때문이다. 그리고 각 패키지는 계층구조를 가지고 최 상위의 계층은 "" 이다.

전체 로그레벨을 변경시킨다.

.level= FINEST

이제 로그가 남기 시작한다. 모든 로그가 남기 시작한다. eclipse 소스에서 남긴 로그 JVM에서 남긴 로그 이렇게 설정하면 모든 로그가 남기 때문에 내가 원하는 결과는 아니다. 왜냐하면 각 계층별로 로그레벨이 null인경우 상위 계층의 로그레벨을 따르기 때문이다.

원하는 결과를 위하여 다시한번 계층의 로그레벨을 변경시켜보자.


이제 내가 남긴 로그만 INFO 이하의 로그가 남는다.






2009년 11월 21일 토요일

[펌] Thread 세이프한 Singleton(싱글톤) 패턴을 JAVA로 구현하는 방법

이글은 자바서비스넷에서 쓰레드 세이프 싱글톤에 대한 계시물을 펌한 글입니다. 계시물을 링크하지 않고 펌 글로 남기는 이유는 계시물이 너무 뒤로 넘어가 있기도 하거니와 댓글 형태의 글을 정리하는 것이 의미가 있다고 생각하기 때문입니다.

 

쓰레드 세이프 싱글톤을 효율적으로 구현하기 위한 DCL(더블체크락킹)방법이 고안되었었습니다. 그러나 그 방법은 자바의 메모리 모델, 캐슁, 코드 최적화의 문제때문에 제대로 동작되지 않는다는 것이 정설입니다.

 

현재 어떤 플랫폼상에서도 완벽히 동작한다고 보장 받을 수 있는 코드는 세가지가 있습니다.

 

1) static 필드에서 초기화 하는 방법

public class Singleton {

   public static final fSingleton = new Singleton();

   private Singleton() {
   }
}

 

2) 모든 createInstance 메소드를 동기화(synchronized)하는 방법

public class Singleton {

   public static final fSingleton = null;

   private Singleton() {
     ....
   }

   public static synchronized Sington createInstance() {
     if ( fSingleton == null ) {

        fSingleton = new Singleton();
     }
     return fSingleton;
   }
}


3) thread-specific 변수를 사용한 방법

  class Singleton {
    private static Singleton theInstance;

    private static final ThreadLocal tlsInstance =
      new ThreadLocal() {
          public Object initialValue() { return createInstance(); }
        };

    public static Singleton getInstance() {
      return (Singleton)tlsInstance.get();
    }

    private static synchronized Singleton createInstance() {
      if (theInstance == null)
        theInstance = new Singleton();
      return theInstance;
    }
  }

2009년 11월 12일 목요일

JDBC Types와 Java Types, Java Object Types 간의 Mapping

JDBC API를 사용하다 보면 Java Object를 DB TYPE에 맞게 값을 읽어오고 파라미터로 세팅해줄 일들이 많이 생긴다.

 

java,sql.ResultSet의 getXXX methods는 값을 읽어오는 대표적인 경우이고,

java.sql.PreparedStatement의 SetXXX methods 들은 값을 세팅하는 대표적인 경우라고 할 수있다.

 

Mapping이 어떻게 되는 지는  Getting Started with the JDBC APIMapping SQL and Java Types을 보면 테이블로 친절하게 정리가 되어 있어서 말하는 것을 생략하도록 하고 여기서 말하고 싶은 것은 Java Types과, Java Object Types인 경우 서로 Mapping이 다른 이유에 대하여 설명하고자 한다.

 

간단하게 설명하면 Java Object Types과 JDBC Types 타입간의 Mapping은 setObject 및 getObject 인 경우 사용하는 Mapping이다. 그외의 setString, setShort와 같은 Method를 사용할 경우에는 Java Type과 JDBC Types 간의 Mapping을 사용한다.

 

두가지가 거의 내용이 대동소이 하지만 JDBC Types이 BIT, TINYINT, SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE 인경우 차이가 나고 그 이유는 Java Type은 primitive  타입(ex int)과 매핑되고, Java Object Types은 wrpa Object(ex Integer)와 연결되는 식으로 변경된다는 점이다. 특히 특이한것은 TINYINT, SMALLINT인데 Java Type에서는 각각 byte와 short 로 Mapping 되나 Java Object Type에서는 모두 Integer로 연결된다. Byte와 Short가 있는데도 불구하고 이렇게 되는 이유는 솔직히 모른다. 나중에 알게되면 글을 수정하도록 하겠다.

 

참고로 JDBC Type은 java.sql.Types에 정의되어 있다.