https://saddr.xyz 

 

Shorten URL

Shorten URL

saddr.xyz

 

내가 직접 만든 사이트. 무려 무료!

<Selection Sort>

<서론>

내가 프로그래밍 로직에 눈 뜨게 해준 소중한 알고리즘이다.

 

물론 자바를 배우는 지금은 동적할당인 Vector 클래스를 이용해서

Sort() 메소드만 사용하면 단 한 줄 만으로 Sort가 되지만 중요한건

프로그래밍 로직을 이해하기 위해 만들어 보는 것이다.

 

 

<본론>

우선 처리순서와 어떠한 알고리즘으로 돌아가는지 간단히 생각해보자.

Selection Sort는 Sort 중에 가장 단순하면서 가장 느린 Sort이다.

 

첫번째 자리부터 일일이 하나하나 찾아가서 조건이 맞으면 큰 수를

오른쪽으로 보내는 로직이다. 그럼 일단 왼쪽 오른쪽 바꾸는 로직이 필요하겠군.

 

변수 : a[배열], temp

연산자 : >  (왼쪽이 크면)

 

실행문

-  temp = a[i]

    a[i] = a[j]

    a[j] = temp

또는

- a[i] ^= a[j]

    a[j] ^= a[i]

    a[i] ^= a[j]

 

(배열 좌측과 우측을 뒤바꾸는 실행문)

 

클래스 : System.in, Scanner 등등

 

우선 임의의 수 5개를 적어보자.

1004, 40, 486, 50, 20

 

 Selection Sort는 일일이 하나하나 비교하는 거니깐..

1004와 40을 비교하고.. 다음은 1004와 486을 비교, 다음 50, 20 이렇게 비교..

그럼 1부터 5까지 실행하는 제어문이 필요하겠군.. 만만한게 for 다..

 

for(int i=0; i<5; i++) {

처리

}

 

뭐 요런 형태겠군.. 근데 하나로는 안될 거고..

for(int i=0; i<5; i++) {

    for(int j=i; j<5; j++) {

    }

}

이렇게 처리해야겠지?

 

아참... 근데 (1번째) > (1번째)가 아니라 (1번째) > (2번째) 부터 시작을 해야 되고

마지막엔 (4번째) > (5번째) 로 비교를 끝내야 하니까 옵션을 좀더 주면

 

for(int i=0; i<5-1; i++) {

    for(int j=i+1; j<5; j++) {

    }

}

 

대략 이정도가 되겠군... 일단은 생각했던걸 적어보자..

 

int a[] = {1004, 40, 486, 50, 20};
int temp;
for(int i=0; i<a.length-1; i++) {
    for(int j=i+1; j<a.length; j++) {
        if(a[i] > a[j]) {
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
    }
}
for(int i : a) {
    System.out.print(i + "  ");
}

 

야호~ 다 만들었다~

로컬에서 잘 돌아가는 SQL 프로시져 구문이

웹호스팅에서 실행하면 계속 요청만할 뿐 connection이 이루어지지 않고

무한대기상태에 빠져린다.

 

버그리포팅을 보니 jdk1.6.0_29 버전 에서 mssql2008을 사용할 때

connection hang이 발생한다고 한다. 이때는 버전업을 해야한다.

jdk1.6.0_31 이상의 최신버전으로..

 

만약 호스팅업체에서 웹서비스를 하고 있다면 버전업을 요구해야 한다.

돈받고 서비스해주는 곳인데 그건 당근 처리해주지~

 

대신 DB 및 소스 백업은 확실하게 해주고 나서 버전업을 신청해야 한다.

여러가지 이유가 있겠지만,

원칙적으로는 바이너리 데이터의 손실을 막기 위해서입니다.

 

바이너리 데이터는 문자열 형태로 변환하면 데이터 손실이 있습니다.

 

예를 들어 C:/Windows/System32/keyboard.drv 라는 파일의 데이터를 읽어 

다른 곳으로 전송해줘야 하는데 바이너리 형태로 전송할 방법이 없을 때는

어떻게 해야 할까요..

 

그럴 때 사용하는 방법 중 하나입니다. 

 

Base64로 인코딩 한 다음에 보내주고,  

그 곳에서는 Base64 디코딩을 이용해 데이터를 복원 하게 됩니다.

이렇게 하면 데이터 손실을 막을 수 있지요.

 

byte를 String 형태로 바꾸면 어떻게 될까요?

간단한 예제를 만들어 보았습니다.

 

 

public static void main(String[] args) throws IOException {
    File file = new File("C:/Windows/System32/keyboard.drv");
    FileInputStream fin = new FileInputStream(file);
    
    int read = -1;
    byte[] bt = new byte[1024];
    String str="";
    while((read=fin.read(bt))!=-1) {
        str += new String(bt, 0, read);
    }
    
    fin.close();
    System.out.println(str.getBytes().length);
}

 

 

원본 파일은 2,000 byte인데  

String 형태로 저장하니 2,406 byte가 되어버리네요.

 

반대로 String 형태가 아닌 Binary로 저장하는 방법을 사용해보겠습니다.

 

public static void main(String[] args) throws IOException {
    File file = new File("C:/Windows/System32/keyboard.drv");
    FileInputStream fin = new FileInputStream(file);
    
    int read = -1;
    byte[] bt = new byte[1024];
    
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    while((read=fin.read(bt))!=-1) {
        bos.write(bt, 0, read);
    }
    
    bos.close();
    fin.close();
    System.out.println(bos.toByteArray().length);
}

 

어떤가요? 2,000 byte 그대로지요?

왜 그럴까요? 아주 기본 상식이지만 다시 짚고 넘어가자면

기본적으로

char 데이터는 non-signed 1byte : 양의 정수 (0~255 표현)

​byte 데이터는 signed 1byte : 그냥 정수 (-128~127 표현)

이기 때문에 음수로 된 byte 데이터는 char가 못 알아먹습니다.

"​난 byte. char에게 -20(ec)을 주었다."

=> ​"난 char. byte한테 ​236(ec)을 받았다."

​라고 해석해버리게 되는거죠. 그래서 데이터 손실이 일어나는 겁니다.

그리하여 이 데이터를 일정한 규칙에 따라 변환한 뒤 전송해야 하는데

이러한 방법 중 하나가 Base64 인코딩입니다. Base64로 전송되면

​받는 곳에서는 다시 byte 데이터로 복구를 해야 하죠.

그러므로 당연히

 

1. Base64 인코딩 - 파라미터 : byte[] , 리턴유형 : String,

2. Base64 디코딩 - 파라미터 : String , 리턴유형 : byte[]

라는 결과가 나오는 것입니다.

최근 ​잘 돌아가던 톰캣이 갑자기

OutOfMemery를 내뿜으며 종료되는 사건이 비일비재 하게 되어

메모리 누수관리에 대한 심각성을 새삼 깨닫게 되었습니다.

​평소에

"자바는 가비지컬렉터가 있어. 알아서 메모리 반환을 잘해줄거야"

라고 생각하던 ​사람중에 한 사람이었는데

구글 검색 중 여러가지 글들을 보게 되면서

"가비지컬렉터는 ​생각보다 멍청하다"라는 결론을 내리게 되고

소스를 한번 짜봤죠.

자원반납이 얼마나 중요한지...

​우선 소스를 확인해보겠습니다.

예제1)​

public class Test {
    public static void main(String[] args) {
        int total = (int)Runtime.getRuntime().maxMemory();

        
byte[] bytes = new byte[total/2];
        System.out.println(bytes);  

        byte[] bytes2 = new byte[total/2];
        System.out.println(bytes2);  
    }
}

​OOM 을 뱉어내고 종료되는군요.

​이번엔 null 할당을 해보겠습니다.

예제2)

public class Test {

    public static void main(String[] args) {
        int total = (int)Runtime.getRuntime().maxMemory();

        
byte[] bytes = new byte[total/2];
        
System.out.println(bytes);
        bytes = null;

        
byte[] bytes2 = new byte[total/2];
        System.out.println(bytes2);
    }
}

 

 

​OOM이 발생하지 않네요.

​물론 예제1 예제2는 단편적인 예제 소스입니다.

​아래와 같이 메소드 단위로 소스를 구성하면 OOM은 발생하지 않지요.

 

 

예제3)

public class Test {

    public void test() {

        int total = (int)Runtime.getRuntime().maxMemory();
        byte[] bytes = new byte[total/2];
        System.out.println(bytes);
    }

    public static void main(String[] args) {
        Test test = new Test();
  
        test.test();
        test.test();
    }

}

 

이는 아마 메소드 실행이 끝나면 지역변수들의 역할을 끝으로 보고

자원반납이 자동으로 이루어지지 않나 하는 생각을 해봅니다. (당연한가요?)

 

모든 프로그래밍이 예제3 처럼만 구성되어 있다면 좋겠지만

프로그래밍이란건 예측 못하는 상황이 너무 많기 때문에,

많은 자원이 예약된 로직이 시작되기 전에

변수 사용이 끝나면 null할당을 염두에 두어야 할 것입니다.

+ Recent posts