전체 글

[C#] Generic 이란.

2014. 1. 7. 14:54
반응형

클래스 사용시 자료형을 미리 지정하여, 안정성을 보장하고 불필요한 캐스팅을 줄여 주는거 같다.

List interger = new List();  
Class Test <-임시자료형 Template Integer.Add ( x )<- 여기 x에 들어갈 수 있는건 암묵적으로 int로 형변환 가능한 것만 받음.   
foreach (var x in lstInteger) { ... } 하면 x는 자동으로 int로 값이 정해짐.
반응형
반응형

Sonatype Nexus 를 설치 후 몇가지 설정을 해줘야 된다.
관리자로 로그인 한 다음 왼쪽 메뉴중에 Repositories 를 클릭하면 디폴트로 등록된 리파지토리들 목록이 나온다.
먼저 목록중에 Public Repositoires 를 클릭하면 아래쪽에 상세내용이 나오는데 Configuration 탭으로 이동한다.

 

Ordered Group Repositories 에 디폴트로 여러개가 등록도 있을껀데 일단 Maven Central 만 남기고 다 빼버리자, 나중에 원하는걸 필요할때마다 맨들어서 추가해 주면 된다.

요부분에서도 그동안의 고정관념 때문에 살짝 삽질을 했는데, 나의 고정관념 상으로는 죠렇게 박스 두개가 있으면 오른쪽 박스가 당연히 선택할 대상들이 들어가는 박스라고 생각해서 아무리 설정을 해도 안되는 것이였다 -_-;

외국 사람들은 반대로 생각하나 보다 -_-;  아무튼 결론적으로 하나로 묶어줄 애들은 왼쪽 Ordered Group Repositories 에다 추가시켜주면 된다 -_-

죠렇게 해 준다음에 아래쪽에 Save 버튼을 눌러 저장을 해준다.

고 다음으로 설정할 것은 리파지토리 목록중에 Maven Central 을 설정하는 것이다. 역시 클릭하면 아래쪽에 상세화면이 나오는데 Configuration 탭으로 이동하자.

 

 


여기서 할일은 Download Remote Indexes 가 디폴트로 False 로 되 있을건데 고걸 True 로 바꿔준다음 Save!

Download Remote Indexes 가 True 로 되있으면, Remote Storage Location 으로 설정된 http://repo1.maven.org/maven2 에 접속해서 인덱스 파일을 받아와서 고 인덱스 파일이랑 똑같이 나의 서버에 인덱스를 맨들어 준다.

Save 를 하면 인덱스파일을 다운로드 받아 인덱스를 업데이트 하는 작업이 시작된다. 이 작업이 완료되면 리프레쉬를 한다음에, 상단의 탭중Browse Index 탭을 클릭해보면 전에 하나도 안보이던 목록들이 쪽 생성이 되 있을 것이다.



인덱싱하는 작업이 쪼매 오래 걸리는데 작업이 완료 됬는지 계속 작업중인지 볼려면 왼쪽 메뉴중 Administration > Scheduled Tasks 를 클릭해 보면 알수 있다.

 

 


이 메뉴는 현재 Nexus 에서 돌아가고 있는 Task 를 보거나 아니면 원하는 Task를 스캐쥴링 하도록 등록하는 메뉴인것 같다.

아무튼 Task 목록을 보면 Maven Central 리파지토리의 인덱스를 다운로드 받아서 인덱싱을 하는 작업이 진행중인것을 볼수 있다.

작업이 완료되면 목록에서 사라지는데, 상단의 리프레쉬 버튼을 클릭하다 보면 언젠가는 사라질 것이다. -_-;



인덱싱 작업이 완료되면 이제부터 정상적인 사설 리파지토리 기능을 수행할 수 있다.!!




인덱싱된 결과를 볼려면 Pubic Repositories 를 클릭한다음 Browse Index 탭을 클릭해 보자.

 

 


인덱싱을 하기전에는 안보이던 여러가지 목록들이 간지나게 쫙 펼쳐져 있다.

※ Browse Index 탭에 보여지는 것들은 내가 맨든 사설리파지토리로 제공가능한 디펜던시들이지 아직 나의 서버로 다운로드가 된 상태는 아니다.
※ 나의 서버로 누군가가 디펜던시를 요청하면 일단 최초로 proxy 대상 리파지토리에서 해당 디펜던시를 다운로드 받아 이후 요청부터 캐싱을 하게 된다
※  현재 다운로드 받아 캐싱하고 있는 디펜던시들을 볼려면 Browse Storage 탭을 클릭해 보면 된다.





여기까지만 하면 일단 설정을 대충 다 끝났고 maven 에서 나의 서버를 바라보게 설정만 해주면 된다.

위 스크린샷에서 보면 리파지토리 목록 왼 오른쪽에 있는 Repository Path를 요렇게 pom.xml 파일의 repository 로 설정해 주거나 바꿔주면 된다.

많은 현재 디폴트로 등록된 리파지토리들이 많이 있지만 이중에서 다른 리파지토리들을 하나로 묶어주는 group 타입의 public 리파지토리를 메이븐에서 바라보도록 설정하자~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<repositories>
    <repository>
        <id>central</id>
        <releases><enabled>true</enabled></releases>
        <snapshots><enabled>true</enabled></snapshots>
    </repository>
</repositories>
 
<pluginRepositories>
    <pluginRepository>
        <id>central</id>
        <releases><enabled>true</enabled></releases>
        <snapshots><enabled>true</enabled></snapshots>
    </pluginRepository>
</pluginRepositories>



Nexus 설명서를 보면 maven 의 settings.xml 파일인가 고걸 수정하게 하던데 그러면 다른 개발자들도 settings.xml 을 귀찮게 수정해야 하기 때문에 나는 svn으로 공유되는 pom.xml 파일을 수정했다.


아무튼 요렇게 한 후 나의 서버가 잘 돌아가나 테스트를 해보기 위해 pom.xml 파일에 디펜던시를 아무거나 하나 추가해 보자.

1
2
3
4
5
<dependency>
    <groupId>abbot</groupId>
    <artifactId>abbot</artifactId>
    <version>0.12.3</version>
</dependency>




음~ 잘되는 것 같다. 확실히 확인하기 위해서 위에서 설명했던 현재 캐싱된 디펜던시들을 보여주는 Browse Storage 탭을 클릭해 보면 pom.xml 파일에 추가했던 abbot 뭐시기가 캐싱된 것을 확인할 수 있다.

 

 



지금까지 한 설정은 딸랑 maven central 리파지토리만 바라보도록 설정했는데, 필요에 따라 다른 외부 리파지토리를 proxy 타입으로 추가 시킨다음

하나로 묶어주는 기능을 하는 group 타입의 Public Repositories 에다 포함 시켜주고 maven 에서는 이 public 리파지토리만 바라보도록 하면

pom.xml 파일에 추가적으로 <repository/> 를 추가할 필요도 없고 한번 캐싱된건 나의 서버에서 빠르게 다운로드 받을 수 있을 것이다.

 

http://stove99.tistory.com 퍼옴.

반응형
반응형

ERWIN을 쓸일이 있어서 이것저것 찾아보다.. 아주 기초적으로 정리를 잘 해놓은 파일이 있어서 공유 합니다.

문제 있다면 내리구요~~~

1. Er-win 설치 : 는 생략... 그냥 설치하는 것은 어렵지 않아요
2. Er-win 표기 방식 : IE 와 Ideflx 에 대한 설명
3. 엔티티 생성 방법
4. 식별/비식별, 다대다 관계 예제 
 ***   관계(Relationship) : 두 Entity간의 업무적인 연관성
  1) 식별관계( Identifying Relationship) 
    - 부모 테이블의 기본키 or 복합키가 자식 테이블의 기본키 or 복합키의 구성원으로 전이되는 식별 관계
      (부모가 자식의 모든 정보를 저장하게 됨)
  2) 비식별관계(Non Identifying Relationship)
     - 자식 테이블의 일반 속성(Attribute) 그룹의 구성원으로 전이 되는 비식별관계(부모는 자식의 부분적인 정보를 표현함)

   * A Table이 부모이고, B Table이 자식Table 일때, B에서 FK
     (A와 B를 연결해주는 컬럼, 즉 A의 PK이냐 아니냐에 따라 식별관계와 비식별 관계로 나뉘게 됨.)
   * 식별관계는 B테이블은 A테이블에 종속적이 되어서 A의 값이 없으면 B의 값은 무의미해 지는 것인 
      반면에 비식별관계는 A 의 값이 없더라도 B의 값은 독자적으로 의미를 가짐.

 ERD를 작성할 때 필요한 관계 카디낼리티와 선택성의 표시 기호와 의미는 다음과 같습니다.
1. 실선 : 식별관계 - 부모테이블의 PK가 자식테이블의 FK/PK가 되는 경우
2. 점선 : 비식별관계 - 부모테이블의 PK가 자식테이블의 일반속성이 되는 경우
3. O : Optional(선택) - 0개가 될 수 있다.
4. | : Mandatory - 1개가 될 수 있다.
5. ^ : Many - 여러개가 될 수 있다.
6. - : Exactly - 정해진 개수만 될 수 있다.

5. 슈퍼 타입과 서브 타입
6. 재귀적 관계 정의
7. Erwin Domain 설정  : 이것 말고 사실 Naming 설정하는 것도 있는데 이거 정말 편함.(http://www.dator.co.kr/eyelevel/textyle/218797)
8. Erwin 
물리적 DB 모델링 설계 방법 
9. 인덱스 정의 
10. 스키마 생성...

 

간략 목차 정리 드렸습니다.
감사합니다.

 마지막으로 다시 정리 하면

식별관계(Identifying Relationship)
 부모 엔티티의 주식별자(PK)는 관계(Relationship)을 통해 자식 엔티티의 외부식별자(FK)로 이주하고, 이주한 부모의 주 식별자(PK)는 자식의 주 식별자(PK)의 일부가 된다. -> (PK,FK)
자식은 각 인스턴스를 식별하기 위해 부모에 종속적이고, 부모 없이는 존재할 수 없다.

비식별관계(Non-Ientifying Relationship)
-  
부모 엔티티에 종속적인지 비종속적인지의 여부에 따라 다시 두 가지 관계로 나뉜다.


비식별종속관계 (Non-Identifying Mandatory Relationship)
부모의 주 식별자는 자신의 non-key 영역으로 이주하고, 자신을 식별하는 데 관계하지 않는다.
자식은 자신의 각 인스턴스의 식별을 위해 부모 엔티티에 독립적이고, 부모 없이 존재할 수 없다.
비식별비종속관계(Non-Identifying Non-Mandatory Relationship)
부모의 주 식별자는 자신의 non-key 영역으로 이주하고, 자신을 식별하는 데 관계하지 않는다.
자식은 자신의 각 인스턴스의 식별 위해 부모 엔티티에 독립적이고, 부모없이 존재할 수도 있다.

http://kimseunghyun76.tistory.com 퍼옴.

반응형

'Database & NoSQL > DB' 카테고리의 다른 글

오라클 잡 관리(Oracle job manage)  (0) 2014.01.28
oracle job 생성  (0) 2014.01.28
오라클 데이터 이동(merge)  (0) 2014.01.02
오라클 세로행을 가로 출력(LISTAGG)  (0) 2013.03.22
오라클 시간 연산(SYSDATE)  (0) 2013.03.22
반응형

이번글은 MERGE 문을 이용해 데이터를 이동시켜보는 방법에 대해서 알아보겠습니다.

MERGE 문은 오라클 9i 버전부터 사용하실 수 있습니다.

MERGE문은 언제 쓰면 될까요?



위의 그림처럼 테이블1의 데이터를 테이블2로 복사하려고 합니다.

그런데 테이블1의 내용 중 몇개가 테이블2에 들어있기때문에 INSERT를 하려면 에러가 발생하게 되어 UPDATE 문으로 처리를 해주어야합니다.

하지만 MERGE문을 이용하면 테이블1과 테이블2를 비교하여 테이블1의 내용이 테이블2에 존재하면 UPDATE 존재하지않으면 INSERT 시켜줄 수 있습니다.
(프로그래밍 언어의 IF ~ ELSE ~ 문과 비슷합니다.)

그럼 이제 사용법을 알아보겠습니다.

일단 2개의 테이블을 만들었습니다. 두 테이블에는 NO, NAME, AGE 3개의 컬럼을 가지고 있습니다.

 


일단 1번 테이블 TEMP_TAB_1 테이블에 데이터를 입력했습니다.

DECLARE ~ BEGIN ~ END; 는 PL/SQL 문법으로 아직 설명한적은 없지만 INSERT INTO를 9번 실행하기가 귀찮아서 그냥 썼습니다.

지금 중요한건 이게 아니니까 사용법만 알려드리겠습니다.

ed or edit 명령어를 이용해서 버퍼(이곳에는 바로전에 사용되어진 명령어가 저장되어있습니다.)를 불러와서 다음과 같이 입력합니다.
(아래의 내용은 이 글 처음의 MERGE 예제 텍스트 파일에 첨부되어있습니다. )

 


 ※ ED or EDIT 명령어를 사용했는데 아래와 같이 나올경우는 버퍼에 아무런 내용이 안들어있기 때문입니다.
    이때에는 select 1 from dual; 같은 명령어를 한번 입력하고 불러오시면 됩니다.

 


입력한 후에 R 또는 RUN 명령어를 사용하여 버퍼에 기록되어진 쿼리를 실행합니다.

그럼 테이블1에 데이터입력 끝!

 


테이블 2에는 테이블1의 일부내용만 입력합시다.


이제 극단적인 예를 들어보겠습니다.

 사장님이 TEMP_TAB_2 에 TEMP_TAB_1의 내용을 복사해서 다 집어넣으라고 하시는군요?

거기다가 이름앞에는 소녀시대_ 를 집어넣고 나이는 해가 지났으니 1살씩 더 추가하라고 하십니다. 어찌해야할까요..

사장님이 이렇게 쉬운문제를 줄리는 없지만 이럴때 MERGE 문을 사용하면 됩니다.

다음이 MERGE문의 사용방법입니다.


MERGE INTO 복사당할테이블명 테이블별칭
   USING 복사할테이블명 테이블별칭
   ON (JOIN 조건)
WHEN MATCHED THEN                                       --복사당할 테이블에 복사할 테이블 데이터가 들어있을경우
   UPDATE SET
            t2.name      = '소녀시대_' || t1.name
           ,t2.age         = t1.age + 1
WHEN NOT MATCHED THEN                               --복사당할 테이블에 복사할 테이블 데이터가 없을경우
   INSERT VALUES(
             t1.no
           , '소녀시대_' || t1.name
           , t1.age + 1
   )

※ INSERT(컬럼명1, 컬럼명2, ...) VALUE(컬럼1내용, 컬럼2내용, ..) 처럼 일부컬럼에만 INSERT 할 수도 있습니다.
※ USING ON은 이전글인 [Oracle] Join 방법에 대해 알아봅시다 에서 4번 JOIN-ON 과 같은 형식입니다.

다음은 실행결과입니다. 테이블1의 내용이 테이블2로 정상적으로 복사된것을 보실 수 있습니다.


http://breadshuttle.tistory.com/ 퍼옴.

반응형

jquery hover 효과

2013. 12. 20. 09:31
반응형
hover 처리

Untitled Document


반응형
반응형

Java 성능 개선을 위한 Programming 기법

JDK 1.3 버전 이후로 지원되는 Hotspot VM은 기본적으로 Heap에 동적으로 할당된 Object는 거의 회수할 수 있다고 한다. 하지만 이 기능으로 인해서 VM은 엄청난 OverHead를 가지게 된다. 무리한 Object의 생성은 생성 당시에도 많은 OverHead를 초래하지만, 생성된 Object를 회수하기 위해서는 더 많은 작업이 요구된다. 이를 해결하기 위한 몇가지 Tip이 있는데, Avoiding Garbage Collection, Object 재사용, static instance variable의 사용에 의한 단일 클래스 인스턴스 구현 방법 등이 그것이다. 핵심은 가능한 Object 생성을 피하자는 것이다.

 
1. Avoiding Garbage  Collection(static Method 사용)

1
2
3
4
5
6
7
8
에졔1)
String str = "55";
int num = new Integer(str).intValue();
  
  
예제2)
String str = "55";
int num = Integer.parseInt(str);


예제1) 에서는 Integer 클래스를 생성한 다음 str에서 정수값을 추출해냈다. Object를 생성하고 초기화하는 과정은 상당한 CPU 집얍적인 작업이고, Heap 영역에 Object가 생성되고 수집되기 때문에 가비지 컬렉터 작업을 수반한다. 가능한 예제2)처럼 Object의 Instance가 필요 없는 static메소드를 사용한다. 


2. Avoiding Garbage Collection(임시 Object 생성 금지)

가장 흔한 예로 String Object의 append를 위해서 (+) 연산을 사용하는 것을 들 수 있다. (+) 연산자를 사용해서 String Object를 append할 경우 우리가 생각하는 것보다 훨씬 더 많은 임시 Object가 생성되고, 가비지 컬렉터에 의해 다시 수집된다. String Object의 append 연산을 위해서는 StringBuffer 클래스를 사용한다. 
1
2
3
4
5
6
7
8
9
10
11
예제1)
String str = "Hello ";
str = str + "World"
System.out.println(str);
  
  
예제2)
StringBuffer str = new StringBuffer();
str.append("Hello ");
str.append("World");
System.out.println(str.toString());

어떤 메소드는 Object의 복사본을 반환하는 경우가 있다. 대표적인 예로 String 클래스의 trim() 메소드를 들 수 있다. trim() 메소드가 수행되면 기존의 Object는 수집되고, 기존 Object의 복사본이 사용되게 된다. 임시 Object 생성과 복사본을 반환하는 메소드가 루프 안에서 사용될 경우 무수히 많은 Object가 생성되고 수집되기 때문에 심각한 문제를 야기하게 된다. 루프 내부에서 Object를 생성하는 것은 가급적 피해야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
예제3)
for(int i = 0; i < 1000; i++) {
    Date a = new Data();
    ...
}
  
  
예제4)
Date a;
for(int i = 0; i < 1000; i++) {
    a = new Date();
    ...
    a = null;
}

예제3)과 예제4)는 현재 날짜와 시간을 얻어오기 위해 루프 안에서 Object를 생성했다. 보통 set으로 시작하는 메소드는 Object의 Instance 값을 재정의한다. API를 충분히 참조한 다음 지원 메소드가 없을 경우, 클래스를 상속 받아 요구에 적합한 메소드를 만드는 방법도 고려할 필요가 있다. 기존 API를 이용한 Object 초기화 방법은 아래 Object 재사용(메소드를 사용한 Object 초기화) 부분 참조.


3. Avoding Garbage Collection(primitive data type 사용)
Date 클래스나 String 클래스의 값들 중 int나 long형으로 표현하여 사용할 수 있는 경우가 있다. 예를 들어

1
2
String a = "1492";
String b = "1997";

과 같을 경우 a와 b는 굳이 String형으로 표현하지 않아도 된다. 하지만 여기서 주의할 점은 Object의 값을 기본 데이터형으로 Casting하는 작업이 오히려 시간이 더 많이 걸릴 수도 있는 것이다. 클래스의 인스턴스 변수로 기본 데이터형을 사용하면 Object의 크기도 줄어들고 Object 생성 시간도 줄일 수 있다.

4. Object 재사용(Pool Management)
Object 재사용 기법으로 흔히 Pool Management 기법을 사용한다. 이는 임의 갯수의 Object를 미리 생성해두고 이를 Vector 클래스를 사용해서 관리하는 방법이다. 해당 Object를 사용하기 위해서 Pool의 Vector에 있는 Object를 하나 가져오고, 다 사용하고 나면 다시 Pool에 반납한다. 이는 기존에 공개되어 있는 Hans Bergsten의 Connection-Pool의 PoolManger클래스에서 사용되고 있다.(Professional JAVA SErver Programming. 정보문화사. 2000.4.4. 제 9장 연결풀링 부분) Object Pool을 사용할 경우, 반환되는 Object가 초기화되어 반환되지 않을 경우 다음에 Pool에서 Object를 가져와서 사용하게 되면 문제를 야기할 수 있기 때문에 초기 클래스 Design시 꼼꼼하게 따져봐야 한다.


5. Object 재사용(메소드를 사용한 Object 초기화)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
예제1)
StringBuffer sb = new StringBuffer();
sb.append("Hello");
out.println(sb.toString());
sb = null;
  
sb = new StringBuffer();
sb.append("World");
out.println(sb.toString());
  
  
예제2)
StringBuffer sb = new StringBuffer();
sb.append("Hello");
out.println(sb.toString());
sb.setLength(0);
sb.append(" World");
out.println(sb.toString());

예제1)과 같이 사용할 경우 하나의 인스턴스 변수를 사용하기는 하지만 두 번의 초기화 과정을 거치게 된다.
예제2)와 같이 각 클래스에서 지원해 주는 메소드를 사용하여 Object를 재사용할 수 있다.


6. static instance variable의 사용에 의한 단일 클래스 인스턴스 구현
다음은 Hans Bergsten의 PoolManager 클래스 코드 중 일부다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class PoolManager {
    private static PoolManager instance;
    ...
    private PoolManager() {
        init();
    }
  
    public static synchronized PoolManager getInstance() {
        if (instance == null) {
            instance = new PoolManager();
        }
  
        ...
          
        return instance;
    }
  
    private void init() {
        ...
    }
}

PoolManager형의 인스턴스가 static으로 선언되어 있다. getInstance() 메소드는 현재 생성되어 있는 PoolManager의 Object를 조사하고 만약 Object가 있으면 Object를 반환하고 없으면 생성자를 호출해서 PoolManager의 Object를 생성한 후 반환한다. 결국 JVM 내부에는 하나의 PoolManager Object가 존재하게 된다. 단일 클래스 인스턴스 기법을 사용할 경우 하나의 인스턴스를 사용하기 때문에 해당 인스턴스의 무결성 부분이 문제가 된다. 이를 위해 다양한 Synchronization 기법을 사용하게 된다. 아래 I/O 퍼포먼스 개선 부분 참조.


7. clone() 메소드 사용으로 Object 생성에 따른 OverHead를 피함

1
2
3
4
5
6
private static int[] data = new int[2][2];
  
int[] someMethod(){
    int[] a = (int[])this.data.clone();
    return a;
}

대부분의 클래스들에는 clone() 메소드가 존재한다. clone() 메소드가 호출되면 Object의 복사본을 반환하는데, 대신 클래스의 생성자를 호출하지 않기 때문에 생성자 호출에 의한 OverHead를 피할 수 있다. clone() 메소드를 사용할 때의 trade-off 문제는 다음 예제를 참조할 것.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static int[] Ref_array1={1,2,3,4,5,6,7,8,9};
static int[][] Ref_array2={{1,2},{3,4},{5,6},{7,8}};
  
//faster than cloning
int[] array1={1,2,3,4,5,6,7,8,9}; 
  
//slower than initializing
int[] array1=(int[])Ref_array1.clone(); 
  
//slower than cloning
int[][] array2={{1,2},{3,4},{5,6},{7,8}};
  
//faster than initializing 
int[][] array2=(int[][])Ref_array2.clone();



8. Method Inline에 의한 method 호출 감소

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
예제1)
public class InlineMe {
    int counter = 0;
      
    public void method1() {
        for (int i = 0; i < 1000; i++) {
            addCount();
            System.out.println("counter=" + counter);
        }
    }
  
    public int addCount() { 
        counter = counter + 1;
        return counter;
    }
  
    public static void main(String[] args) {
        InlineMe im = new InlineMe();
        im.method1();
    }
}

예제1)에서 addCount() 메소드를 다음과 같이 수정하면

1
2
3
public void addCount() {
    counter = counter + 1;
}

위와 같이 수정할 경우 addCount() 메소드는 컴파일시 Inline 되어서 실제 메소드를 호출하지 않고 같은 결과를 반환한다.
즉 method1()이 실제 수행될 때는 다음과 같이 수행.

1
2
3
4
5
6
public void method1() {
    for (int i = 0; i < 1000; i++) {
        counter = counter + 1;
        System.out.println("counter=" + counter);
    }
}



9. 생성자 설계
예제1, 2, 3) 모두 같은 역할을 하는 생성자들로 구성되어 있다. 하지만 퍼포먼스 측면에서 보면 예제3)이 가장 효율적이다. 하지만 클래스를 설계 할 때는 예제1)과 같이 해야 할 때도 있다. 클래스가 요구하는 조건에 따라 생성자의 설계 방법이 다르겠지만, Object를 생성할 때 가능한 생성자를 적게 호출하는 방법을 사용하는 것이 퍼포먼스 면에서 좋다는 것은 당연한 일이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
예제1)
class SlowFlow {
    private int x, y;
      
    public SlowFlow() {
        this(777);
    }
      
    public SlowFlow(int x) {
        this(x, 778);
    }   
      
    public SlowFlow(int x, int y){
        this.x = x;
        this.y = y;
    }
}
  
예제2)
class SlowFlow {
    private int x, y;
      
    public SlowFlow() {
        this(777, 778);
    }
      
    public SlowFlow(int x) {
        this(x, 778);
    }
      
    public SlowFlow(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
  
예제3)
class SlowFlow {
    private int x, y;
      
    public SlowFlow() {
        x = 777;
        y = 778;
    }
      
    public SlowFlow(int x) {
        this.x = x;
        y = 778;
    }
      
    public SlowFlow(int x, int y) {
        this.x = x;
        this.y = y;
    }
}



10. "extends" VS "implements"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
예제1) extends
import java.awt.event.*;
import java.awt.*;
  
public class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent we) {
        Container source = (Container) we.getSource();
        source.setVisible(false);
    }
}
  
  
예제2) implements
import java.awt.event.*;
import java.awt.*;
  
public class MyWindowListener implements WindowListener{
    public void windowClosing(WindowEvent we){
        Container sourve=(Container)we.getSource();
        source.setVisible(false);
    }
}
  
public void windowClosed(WindowEvent we){}
public void windowActivated(WindowEvent we){}
public void windowDeactivated(WindowEvent we){}
public void windowIconified(WindowEvent we){}
public void windowDeiconified(WindowEvent we){}
public void windowOpened(WindowEvent we){}

"implements"의 경우에는 특정 메소드를 구현하고 인터페이스에 정의된 모든 메소드를 코딩해야 하기 때문에 코드의 낭비를 초래하는 반면, "extends"의 경우에는 슈퍼 클래스에 정의된 메소드들 중 필요한 메소드만 Overriding 하면 된다. 이 부분은 설계 시 추상 클래스를 사용할 것인지 인터페이스를 사용할 것인지 고려할 것.


11. 클래스 집약

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
예제1)
public class Person {
    private Name name;
    private Address address;
}
  
class Name {
    private String firstName;
    private String lastName;
    private String[] otherNames;
}
  
class Address {
    private int houseNumber;
    private String houseName;
    private String streetName;
    private String town;
    private String area;
    private String greaterArea;
    private String country;
    private String postCode;
}

예제1)에서 정의된 Person 클래스는 Name형의 name과 Address형의 address, 두 개의 인스턴스 변수를 가진다. 클래스를 설계할 때 가능한 클래스의 수를 줄여서 동적으로 생성되는 Object의 수를 줄일 수도 있다. 예제1)에서 정의된 세 개의 클래스는 하나의 클래스로 집약될 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
예제2)
public class Person {
    private String firstName;
    private String lastName;
    private String[] otherNames;
    private int houseNumber;
    private String houseName;
    private String streetName;
    private String town;
    private String area;
    private String greaterArea;
    private String country;
    private String postCode;
}



12. I/O 퍼포먼스 개선
자바에서는 자료를 읽거나 쓰기 위해 Stream을 사용한다. 자바는 두 가지 형태의 Stream을 지원한다.
Reader/WriterInput/OutputStream이 그것이다. Reader/Writer는 High-Level의 I/O(예. String)을 지원하고 Input/OutputStream은 Low-Level의 I/O(byte)를 지원한다. 속도 향상을 위해서는 BufferedStream을 사용한다. BufferedStream을 사용할 경우 버퍼의 기본값은 2k이다. 이 값은 조정될 수 있으나 자료의 용량이 클 경우 메모리가 많이 필요하기 때문에 BufferedStream을 사용할 경우 여러가지 사항을 고려해야 한다.


BufferedStream을 사용하지 않고 I/O를 했을 경우의 예제이다. 370K의 JPEG 파일을 복사하는데 10800ms.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
예제1) Simple File Copy
public static void copy(String from, String to) throws IOException {
    InputStream in = null;
    OutputStream out = null;
  
    try {
        in = new FileInputStream(from);
        out = new FileOutputStream(to);
  
        while (true) {
            int data = in.read();
  
            if (data == -1)
                break;
  
            out.write(data);
        }
        in.close();
        out.close();
  
    } finally {
        if (in != null)
            in.close();
              
        if (out != null)
            out.close();
    }
}


BufferedStream을 사용해서 퍼포먼스를 개선한 예제이다. 예제1)과 같은 파일을 복사하는데 130ms. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
예제2) Faster File Copy
public static void copy(String from, String to) throws IOException {
    InputStream in = null;
    OutputStream out = null;
  
    try {
        in = new BufferedInputStream(new FileInputStream(from));
        out = new BufferedOutputStream(new FileOutputStream(to));
          
        while (true) {
            int data = in.read();
              
            if (data == -1)
                break;
                  
            out.write(data);
        }
          
    } finally {
        if (in != null)
            in.close();
              
        if (out != null)
            out.close();
    }
}


while 루프를 사용하지 않고 배열을 사용함으로써 퍼포먼스를 개선한 예제. 예제1)과 같은 파일을 복사하는데 33ms.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
예제3) Custom Buffred Copy
public static void copy(String from, String to) throws IOException {
    InputStream in = null;
    OutputStream out = null;
          
    try {
        in = new FileInputStream(from);
        out = new FileOutputStream(to);
          
        int length = in.available();
        byte[] bytes = new byte[length];
              
        in.read(bytes);
        out.write(bytes);
              
    } finally {
        if (in != null)
            in.close();
              
        if (out != null)
            out.close();
    }
}
 
하지만 예제3)은 byte 배열로 선언되는 메모리 버퍼의 크기가 실제 파일의 크기와 동일해야 한다. 이에 따라 두 가지 문제점이 발생할 수 있다. 첫 번째는 파일의 용량이 클 경우 상당한 메모리 낭비를 초래한다는 점이다. 두 번째 문제점은 Copy() 메소드가 수행될 때마다 new byte[]에 의해 버퍼가 새로 만들어진다는 점이다. 만일 파일의 용량이 클 경우 버퍼가 만들어지고 Garbage Collector에 의해 수집될 때 상당한 OverHead를 초래할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
예제4) Improved Custom Buffered Copy
static final int BUFF_SIZE=100000;
static final byte[] buffer=new byte[BUFF_SIZE];
  
public static void copy(String from, String to) throws IOException {
    InputStream in=null;
    OutputStream out=null;
  
    try {
        in=new FileInputStream(from);
        out=new FileOutputStream(to);
      
        while(true) {
            synchronized (buffer) {
                int amountRead = in.read(buffer);
                  
                if (amountRead == -1)
                    break;
      
                out.write(buffer, 0, amountRead);
            }
        }
    } finally {
        if (in!=null)
            in.close();
          
        if (out!=null)
            out.close();
    }
}

크기가 100K인 byte배열을 임시버퍼로 지정하고 이를 static으로 선언함으로써 퍼포먼스를 개선했다. 예제1)과 같은 파일을 복사하는데 22ms. static buffere의 사용으로 I/O 작업을 수행할 경우 발생할 수 있는 문제점을 해결하기 위해 synchronized block을 사용했다. 비록 synchronization을 사용함에 따라 성능 저하를 초래하지만, 실제 while 루프에 머무는 시간이 극히 짧기 때문에 퍼포먼스에 문제는 없다. 테스트에 의하면 synchronized 버전과 unsynchronized 버전 모두 같은 시간에 수행을 완료했다.


13. Web 환경에서 Caching을 이용한 자바 퍼포먼스 개선
웹 환경에서 Object Caching 기법은 주로 DB나 파일에서 동일한 내용을 가져오는 루틴에서 사용된다.
DBMS에 SQL문을 던지고 받아오는 부분의 내용이 거의 변동이 없을 경우 요청시마다 매번 SQL문을 실행시켜서 결과를 받아오는 것이 아니라 최초 실행된 값을 그대로 반환하는 기법이다. 그리고 시간 Check 기법을 이용해서 특정 시간 경과 후 요청이 들어오면 이전 요청에 의해 수행되어진 값을 갱신해서 반환한다. 결과에 의한 반환값이 메모리에 부담이 되지 않을 정도로 크지 않은 경우, 실시간으로 변경된 정보를 반환값으로 사용하는 루틴이 아닐 경우 유용하게 사용할 수 있다.



14. Perfomance CheckList
 - 임시로 사용하기 위해 Object를 생성하는 것을 피해라. 특히 Loop에서...
 - 빈번하게 호출되는 메소드에서 Object 생성하는 것을 피하라.
 - 가능한 Object를 재사용하라.
 - 임시 Object의 생성을 줄이기 위해 데이터 타입 컨버전 메소드를 재정의 하는 방법을 고려하라.
 - 메소드 설계 시 데이터를 유지하고 있는 Object를 반환하는 메소드보다 데이터로 채워진 재사용 가능한 Object에 접근하는 메소드를 정의하라.
 - String이나 Object를 Integer로 대치하라. Object 비교를 위해 equals() 메소드를 호출하지 말고 기본 데이터 타입의 == 연산자를 사용하라.
 - 인스턴스 변수로 기본 데이터 타입을 사용하라.
 - 단지 메소드 호출을 위해 Object를 생성하는 것을 피하라.
 - String 연속 연산자 (+)를 사용하는 것보다 StringBuffer 클래스를 사용하라.
 - 복사본을 생성하는 메소드보다 Object를 직접 수정하는 메소드를 사용하라.
 - 생성자는 간단하게... 상속 계층은 얕게 ...
 - 인스턴스 변수를 초기화 하는 것은 한 번 이상 하지 말 것.
 - 생성자 호출을 피하기 위해 clone() 메소드를 사용할 것.
 - 간단한 배열일 경우에는 초기화를... 복합한 배열일 경우에는 clone() 메소드 호출.
 - 프로그램 내부에서 Object 생성 시기를 조절해서 Object 생성에 따른 bottlenecks를 없앤다.
 - 어플리케이션 내부에서 여분의 시간이 허용된다면 가능한 Object를 빨리 생성하라. 생성된 Object를 내부적으로
   유지하고 있다가 요청이 발생하면 할당하라.
 - 사용 가능성이 희박하거나, 분산처리에 의해 Object를 생성할 경우 Object는 생성 시기를 늦춰라.

반응형

+ Recent posts

반응형