2009/02/19 10:15
제 10회 한국자바개발자 컨퍼런스
JCO 에서 컨퍼런스를 개최하는데 이번에 참가할까 생각중입니다.
근데 주위에 같이 갈 사람이...ㅠ.ㅠ
그래도 일단 듣고 싶은 세션을 찍어봣습니다.^^;;

사용자 삽입 이미지

MethodChain과 Ajax 애플리케이션 아키텍처 는 김영보님이 MethodeChain을 처음 발표하실 때부터 주의깊게 살펴보던거라 당연히 듣고 싶고 NHN 기술개방 현황과 nFORGE 개발 이야기 도 nFORGE에 관심을 가지고 있었습니다. Continuous Integration with Hudson Hudson은 okjsp의 세미나를 통해 관심을 갖게 되었죠. 기능 중심의 설계에서 Value 중심의 설계로의 전환  은  강의 설명을 보고 바로 결정했습니다. : )

아... 이제 같이 갈 사람을 수소문 하는 일만 남았습니다.^^;;



크리에이티브 커먼즈 라이선스
Creative Commons License
2009/01/14 01:44

DWR

DWR은 자바 라이브러리로서 Direct Web Remoting의 약자입니다. Java에서 Ajax를 쉽게 사용하기 위한 라이브러리로서 서버에 있는 Java소스를 스크립트로 바로 호출 할 수 있도록 해줍니다. 이는 기존의 다른 Ajax에서 서버에서 데이터를 받아오기 위한 페이지를 만들 필요가 없기 때문에 개발의 편의성을 높여줍니다.

prototype.js

프로토 타입은 모르는 사람이 없을 정도로 유명한 javascript framework입니다. 코드를 간결하게 해주고 웹 브라우저에 따른 별도의 javascript 코드를 작성하지 않아도 됩니다.


DWR VS prototype.js Ajax performance 비교

그렇다면 DWR과 prototype.js의 Ajax 성능은 어떨까요? 직접 테스트 해볼까요?
참고로 이 테스트는 제 개인적인 호기심으로 한 테스트입니다. 테스트 방법 및 신뢰도에 대한 부분은 전혀 보장하지 않습니다. : )

테스트 환경

JRE : 1.6.0_11
브라우저 : FireFox
측정 툴 : FireBug
※ 모든 테스트 결과 수치는 ms(1/1000초)입니다.
테스트 1 : 1초 간격으로 호출을 해서 응답시간을 측정합니다.
이 테스트는 한번의 Ajax 응답이 오는 시간을 측정하는 테스트입니다.

DWR 테스트 결과
사용자 삽입 이미지

 prototype.js 테스트 결과
사용자 삽입 이미지


DWR prototype.js
1 27 47
2 31 26
3 38 29
4 34 32
5 31 56
6 55 57
7 26 23
8 40 45
9 62 50
10 61 48
평균 40.5 41.3
수치상으로만 보면 둘다 비슷 비슷 하네요. 하지만 테스트2에서 부하가 걸린 상황에서는 조금 다를껍니다.
그리고 그림을 보시면 DWR과 prototype.js의 Ajax 방식에서 차이점이 보이실껍니다.
DWR은 POST 방식을 사용하고 있고 prototype.js는 GET 방식을 사용하고 있네요.


테스트 2 : 100번을 연속으로 호출해서 모든 응답이 올때까지의 시간을 측정합니다.
이 테스트는 부하 테스트입니다. 한번에 많은 양의 요청을 얼마나 빨리 처리할 수 있는가를 측정합니다.

DWR 테스트 결과
사용자 삽입 이미지
DWR은 100개의 응답이 오는데 3.38초가 걸렸네요.

prototype.js 테스트 결과
사용자 삽입 이미지
prototype.js는 100개의 응답을 받는데 1.67초가 걸렸네요. 4번째 요청이 제일 늦게 응답을 받았는데 1.67초가 걸렸습니다.

테스트 결과 분석

부하가 걸리지 않는 상황에서는 DWR이나 prototype.js의 성능상의 차이는 거의 없습니다. 하지만 부하가 걸리는 상황에서는 prototype.js의 성능이 DWR보다 월등한 성능을 보여주고 있습니다.
 하지만 이는 GET방식과 POST방식으로 인한 차이일 수도 있으며 DWR과 prototype.js의 메모리 사용률도 조금달랐습니다. DWR은 메모리가 일정 수치 이상 올라가면 메모리 사용량이 일정 수치 이상 올라가지 않는 것으로 보아 가비지 컬렉터가 수행되는 것 갔았으며 prototype.js는 메모리 사용률이 계속 올라갔습니다. 이 부분에 대해서는 별도의 테스트가 필요한것 같습니다.
 만약 Ajax 컴포넌트를 선택하는 상황이라면 성능상으로는 prototype.js이 뛰어날 지라도 DWR의 개발시 편의성과 메모리 사용률도 무시하지 못할 부분이라고 생각됩니다.

※ 참고로 이 포스트에서 보여드린 테스트는 한번 밖에 수행하지 않았지만 결과를 기록하지 않은 테스트가 여러번 수행되었으며 위 결과와 비슷한 수치를 보였습니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
2009/01/09 00:25
 우리는 제일 처음 자바를 배울 때 앞 단원에서 프리미티브 타입과 Wrapper 클래스에 대해서 배웁니다. 그리고 곧 잊어버리게 됩니다. 코딩을 하다 보면 어느순간 부터인가 프리미티브 타입이나 Wrapper 클래스에 대해 생각하지 않고 코딩을 하게 되기 때문입니다. 아니 사실 처음부터 신경쓰지 않고 코딩을 했을지도 모릅니다.

 오늘은 우리가 평소에 신경쓰지 않고 코딩하던 부분에 대해서 다시 한번 생각해보도록 하겠습니다.
다음은 제가 '[String 비교하기] .equals()와 ==은 다른가요?'에서 마지막에 보여드렸던 코드입니다.
public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {
        new Test().testInteger();
    }
    
    public void testInteger() {
        int a = 1;
        int b = 1;
        Integer c = new Integer(1);
        Integer d = new Integer(1);
        System.out.println("1:"+System.identityHashCode(a));
        System.out.println("2:"+System.identityHashCode(b));
        System.out.println("3:"+System.identityHashCode(c));
        System.out.println("4:"+System.identityHashCode(d));
        System.out.println("5:"+(a == b));
//        System.out.println("6:"+a.equals(b));
        System.out.println("7:"+(c == d));
        System.out.println("8:"+c.equals(d));
        System.out.println("9:"+(a == c));
    }
}

이 코드를 실행시키면 다음과 같은 결과를 얻을 수 있습니다.
사용자 삽입 이미지

1번부터 8번까지는 '[String 비교하기] .equals()와 ==은 다른가요?'를 잘 읽어 보셨다면 어느정도 감이 오실껍니다.
 아... '[String 비교하기] .equals()와 ==은 다른가요?'는 기억이 잘 안나신다구요? 그럼 제가 다시  간단하게 요약하자면 여기서 a,b는 프리미티브 타입으로 하나의 '값'이라고 보시면 됩니다. 하지만 c,d는 '값
'이 아니라 '객체'입니다.
 그런데 왜 9번은 결과가 true일까요? 분명히 프리미티브 타입(값)과 Wrapper 클래스를 비교했는데 결과는 왜 같다고 나왔을까요? 그것은 바로 '자동 UnBoxing'에 있습니다. 9번에서는 프리미티브 타입과 Wrapper 클래스를 비교했는데요. 이때 비교 대상이 프리미티브 타입이라는걸 알고 있기 때문에 Wrapper 객체에서 자동으로 값을 꺼내서 프리미티브 타입 대 프리미티브 타입으로 바꿔서 비교해 주는 것입니다.
 이와 반대로 자동 Boxing은 Wrapper 객체가 와야 할 자리에 프리미티브 타입이 오면 프리미티브 타입을 자동으로 Wrapper 객체로 만들어 주게 됩니다. 하지만 '[String 비교하기] .equals()와 ==은 다른가요?'에서 String은 자동 Boxing, 자동 UnBoxing 기능이 없기 때문에 9번처럼 비교하면 당연히 false가 나오게 됩니다.

 글 솜씨도 없고 재미도 없는 포스트 끝까지 읽어 주셔서 감사합니다. 기본기만 하면 너무 심심하니 다음에는 DWR을 이용한 Ajax, Reverse Ajax 사용하기를 한번 포스트 해볼 생각입니다. 많이 기대해 주세요.^^
크리에이티브 커먼즈 라이선스
Creative Commons License
2009/01/03 16:39
 우리는 코딩을 하면서 String을 비교할 때 무의식적으로 아래와 같이 코딩을 합니다.
[code]
aString.equals(bString)
[/code]

 하지만 왜 String을 비교할 때만 이렇게 비교하는지 우리는 알고 코딩을 하고 있는 것일까? int, boolean, long 등은 == 로 비교를 하면서 String은 왜 다를까?

 지금부터  String을 비교할 때 .equals()와 == 이 어떻게 다른지 알아보자.

 일단 코드를 실행해보고 결과를 보면서 진행하겠습니다. 저는 백문이불여일견이라는 말을 좋아하거든요.^^
[code]
public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new Test().testString();
    }

    public void testString() {
        String a = "TEST";
        String b = "TEST";
        String c = new String("TEST");
        String d = new String("TEST");
        System.out.println("1:"+System.identityHashCode(a));
        System.out.println("2:"+System.identityHashCode(b));
        System.out.println("3:"+System.identityHashCode(c));
        System.out.println("4:"+System.identityHashCode(d));
        System.out.println("5:"+(a == b));
        System.out.println("6:"+a.equals(b));
        System.out.println("7:"+(c == d));
        System.out.println("8:"+c.equals(d));
    }
}
[/code]

위 코드를 실행해 보면 결과는 다음과 같이 나옵니다.

사용자 삽입 이미지

결과를 보면 a,b는 hashcode값이 같지만 c,d는 값이 다른 것이 보입니다.
그럼 이번엔 비교한 결과를 볼까요? a,b는 equals()로 비교를 하거나 ==로 비교를 해도 결과는 항상 true 입니다. 하지만 c,d는 equals() 비교를 하면 트루지만 ==로 비교를 하면 false죠.

왜 이런 결과가 나올까요?

 이런 결과가 나오는 이유는 equals()는 비교대상의 문자열 리터럴(값)을 비교하고 ==는 대상 객체를 비교하기 때문입니다. 또한 자바에서는 a,b처럼 같은 값을 가지면 하나의 메모리 주소를 참조하게 됩니다. 즉, a,b의 "TEST"라는 문자열 리터럴은 컴파일되면 String 객체가 되는데 a,b는 같은 메모리 주소를 가지게 됩니다. 하지만 c,d는 처음부터 별도의 String 객체로 생성되었기 때문에 동일한 "TEST"라는 문자열 리터럴을 가지지만 서로 다른 객체가 됩니다.
 무슨말인지 모르시겠다구요? 그럼 그림으로 한번 볼까요?
사용자 삽입 이미지
간단하게 정리하자면 a,b는 문자열 리터럴이 컴파일시에 자동으로 하나의 String 객체가 되고 b,c는 별도의 객체가되어서 문자열 리터럴(값)으로 비교를 하면 a,b,c,d 모두 같지만 객체로 비교를 하게 되면 (a,b),c,d의 3개의 객체가 되는 것입니다.

 여기서 이어지는 또다른 의문점... 프리미티브 타입과 Wrapper 클래스의 비교는 어떻게 될까요?
아래 코드를 한번 돌려 보세요. 8번까지는 위 내용과 비슷하지만 9번 결과는 어떻게 나올까요?
 다음에는 프리미티브 타입과 Wrapper 클래스, 자동 Boxing, 자동 UnBoxing에 대해서 알아 보도록 하겠습니다.

[code]
package net.westzero;

public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new Test().testInteger();
    }
  
    public void testInteger() {
        int a = 1;
        int b = 1;
        Integer c = new Integer(1);
        Integer d = new Integer(1);
        System.out.println("1:"+System.identityHashCode(a));
        System.out.println("2:"+System.identityHashCode(b));
        System.out.println("3:"+System.identityHashCode(c));
        System.out.println("4:"+System.identityHashCode(d));
        System.out.println("5:"+(a == b));
//        System.out.println("6:"+a.equals(b));
        System.out.println("7:"+(c == d));
        System.out.println("8:"+c.equals(d));
        System.out.println("9:"+(a == c));
    }
}
[/code]
크리에이티브 커먼즈 라이선스
Creative Commons License
2008/11/28 13:08

출처 : http://sinuk.egloos.com/2676307

1. JNI (Java Native Interface) 란 ?

- 자바가 다른 언어로 만들어진 어플리케이션과 상호 작용할 수 있는 인터페이스를 제공한다.

- 자바가상머신(JVM)이 원시 메소드(native method)를 적재(locate)하고 수행(invoke)할 수 있도록 한다

- JNI가 자바가상머신내에 포함됨으로써, 자바가상머신이 호스트 운영체제상의 입출력, 그래픽스, 네트워킹, 그리고 스레드와 같은 기능들을 작동하기 위한 로컬시스템호출(local system calls)을 수행할 수 있도록 한다.

* 쉽게 말해 Java와 다른 언어를 연동하는 솔루션입니다.


[그림1] C로 만들어진 Library와 JAVA를 연결해주는 JNI


 

 

2. Why do you need JNI ?


자 바 네이티브 메쏘드(Java Native method, 이하 JNI)는 다른 언어로 작성된 코드를 자바에서 호출하도록 만들어진 규약이다. 현재는 C/C++에 대한 호출만을 정확하게 지원한다. 어떻게 보면 JNI는 자바가 만들어진 철학과 정반대되는 것이다.


그러나. Java에도 한계가 있다.


1. 속도 문제가 있는 계산 루틴
 > 자바가 Native Code(플랫폼에 종속적인 기계어 코드)에 비해 느리다.

2. 자바에서 하드웨어 제어

3. 자바에서 지원되지 않은 특정 운영체제 서비스
 > 자바의 클래스 라이브러리는 방대하고 다양한 서비스를 제공하지만, 특정 플랫폼에서 제공하는 고유의 서비스의 기능을 모두 포함할 수는 없다. 특히, 특수한 목적으로 제작된 하드웨어를 자바에서 제어해야 할 필요가 있다고 한다면, 자바만으로 해결하기는 힘들다.

4. 기존의 프로그램에서 자바가 제공하는 서비스를 이용
 > 기존에 작성된 프로그램이나 기존의 시스템(legacy)과의 연계 문제


∴ JNI를 써서 해결해보자.


 

3. C를 이용한 JNI 예제

VC++을 이용해 C문법으로 작성되어 만들어진 DLL을 로딩하여 Java에서 사용해보겠습니다.


1단계 : Native Method를 선언하는 자바 클래스 작성
2단계 : 1단계에서 작성한 클래스 컴파일
3단계 : javah를 사용해서 Native Method가 사용할 헤더 파일 생성
4단계 : C언어로 Native Method 실제 구현
5단계 : C 코드와 헤더 파일을 컴파일
6단계 : 자바 프로그램 실행


 

1단계 : Native Method를 선언하는 자바 클래스 작성

Java 소스 파일 : HelloJni_Jsource.java


import java.util.*;

class HelloJniClass {
   native void Hello();

  static {  System.loadLibrary("Hello_DLL");   }

  public static void main(String args[]) {   
      HelloJniClass myJNI=new HelloJniClass();
      myJNI.Hello();
   }
}


// 아래는 좀 위의 내용 보충 그림





2단계 : 1단계에서 작성한 클래스 컴파일



* 컴파일시에는 일반 java 컴파일때와 마찬가지로 환경변수 셋팅이 되어 있어야 합니다.
 -> Path가 JDK의 Javac.exe가 있는 폴더에 설정되어 있어야 합니다.



3단계 : javah를 사용해서 Native Method가 사용할 헤더 파일 생성


HelloJniClass.h을 열어보면

JNIEXPORT void JNICALL Java_HelloJniClass_Hello  (JNIEnv *, jobject);
위의 함수를 Implement만 해서 DLL을 만들면 됩니다. (4단계)


4단계 : C언어로 Native Method 실제 구현(1)

1) VC++ 프로젝트 만들기 : Win32용 DLL 프로젝트로 만듭니다.
New - Projects : Win32 Dynamic-Link Library

2) Add Files Projects : HelloJniClass.h 파일 추가

3) Projects Setings(Alt+F7)
   - Link탭에 Output file Name : 1단계의 2. 라이브러리 적재시 작성한 DLL파일명(Hello_DLL.dll)
   - C/C++탭 Preprocessor 카테고리의 Additional Include directories
       JDK의 Include폴더와 Include폴더 밑의 win32폴더

          예) C:\Program Files\Java\jdk1.5.0_03\include\,
             C:\Program Files\Java\jdk1.5.0_03\include\win32




 


4. 값의 전달과 리턴

 

1단계 : Java 소스 파일 StringPass_Jsource.java
* 일반 자바 메쏘드 선언과 동일합니다.

class JNI_Message {
   native byte[] Message(String input);

  // 라이브러리 적재(Load the library) 

  static {
    System.loadLibrary("Msg_DLL");
  }


  public static void main(String args[]) {   
 byte buf[];

    // 클래스 인스턴스 생성(Create class instance)
    JNI_Message myJNI=new JNI_Message();

    // 원시 메소드에 값을 주고 받음
    buf = myJNI.Message("Apple");
 
 System.out.print(buf); // 받은값 출력
 }
}



2단계 : 컴파일
 javac StringPass_Jsource.java

 

3단계 : header파일 생성
 javah JNI_Message


4단계 : method구현 : StringJNIDLLSource.c

#include <stdio.h>
#include <jni.h>
#include <string.h>
#include "JNI_Message.h"

JNIEXPORT jbyteArray JNICALL Java_JNI_1Message_Message (JNIEnv * env, jobject jobj, jstring input)
{
    jbyteArray jb;
    jboolean iscopy;
    char* buf;
    static char outputbuf[20];

    buf=(*env)->GetStringUTFChars(env, input, &iscopy);  // 입력 String 읽어오는 함수
    printf ("\nDLL receive Data from JAVA : %s\n",buf);   // 입력받은 내용을 출력
    strcpy(outputbuf,"Delicious !!\n");
    jb=(*env)->NewStringUTF(env, outputbuf);  // 출력할 내용의 java버퍼에 output버퍼값을 셋팅

   return(jb); // java버퍼 리턴
}



(*env)->함수명 형태로, JAVA의 메쏘드를 C에서 이용할수 있습니다.
* JAVA는 C로 문자열을 넘겨줄때 UTF-8형태를 사용합니다.



5단계 : 실행

C:\test\C_JNI\Paramerter Pass>java JNI_Message

DLL receive Data from JAVA : Apple
Delicious !!





5. KVM ? KNI ?

KVM은 J2ME의 일부로서 작고 자원이 한정된 기계장치를 위해 설계된 소형 JVM.
JVM에서는 JNI가 KVM의 KNI가 있다.


 

6. 기타프로그래밍 이슈들
참고 URL :http://www.javastudy.co.kr/docs/jhan/javaadvance/jni.html

언어적 이슈(Language Issues)
메소드 호출(Calling Methods)
필드의 참조(Accessing Fields)
스레드와 동기화(Threads and Synchronization)
메모리 이슈(Memory Issues)
수행(Invocation)
스레드 연결(Attaching Threads)

크리에이티브 커먼즈 라이선스
Creative Commons License