영역 바이너리 옵션 타입

마지막 업데이트: 2022년 1월 28일 | 0개 댓글
  • 네이버 블로그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 트위터 공유하기
  • 카카오스토리 공유하기
기존의 "https://" 라는 문자열을 레퍼런스 하고 있는 변수는 아무것도 없으므로 Unreachable 오브젝트가 된다.

영역 바이너리 옵션 타입

버퍼 오버플로우를 모니터하기 위해 버퍼와 제어 데이터(SFP) 사이에 설정된 값; 버퍼 오버플로우가 발생하면 canary의 값이 손상되고 canaries 데이터의 검증에 실패해 오버플로우에 대한 경고가 출력되고 손상된 데이터를 무효화 처리한다.

버퍼 Canary SFP

△ 카나리가 적용된 경우 스택 구조

Canaries의 종류

➰ Terminator Canaries

canary 값을 문자열의 끝을 나타내는 문자들 -NULL(0x00), CR(0x0d), LF(0x0a) EOF(0xff)-을 이용해 생성한다.

공격자가 이 canaries를 영역 바이너리 옵션 타입 우회하기 위해서는 return address를 쓰기 전에 null 문자를 써야한다 . null 문자는 overflow를 방지하게 한다. (strcpy()함수는 null 문자의 위치까지 복사) 그럼에도 불구하고 공격자는 잠재적으로 canary를 알려진 값으로 겹쳐쓰고 정보를 틀린 값들로 제어해서 canary 검사코드를 통과할 수 있게된다.

➰ Random Canaries

canary 값을 랜덤하게 생성한다. (일반적으로 exploit을 통해 canary의 값을 읽는 것은 불가능하다.) 생성되고 난 후 프로그램 초기 설정 시에 전역 변수에 값이 저장된다. 보통 매핑되지 않은 페이지에 저장한다. 해당 메모리를 읽으려고 하면 segmentation fault가 발생하면서 프로그램이 종료한다.

공격자가 canary의 값이 저장된 스택 주소를 알거나 스택의 값을 읽어올 수 있는 프로그램 이 있다면! canary의 값을 확인할 수는 있다.

➰ Random XOR Canaries

canary 값을 모든 제어 데이터 또는 일부의 제어 데이터를 사용해 XOR scramble 하여 생성한다. canary의 값과 제어 데이터가 오염됐을 때 canary의 값이 달라진다.

random canaries와 마찬가지이지만, random 보다는 stack에서 canary의 값을 읽어오는 방법이 조금 더 복잡하다. 공격자가 canary를 다시 인코딩하기 위해서는 original canary의 값 + 알고리즘 + 제어 데이터 가 필요하다.

Example -64bit

gets 함수를 호출하는 부분과 canary 값 저장하는 위치에 break point 설정한다 실행

rdi 레지스터: 0x7fffffffddd0 => 사용자 값이 저장되는 영역이다

ni 하고 "A"*32 입력

사용자 값이 저장되는 영역(0 x7fffffffddd0 )에 "A"*32의 문자열을 저장한다.

c

mov rax, qword ptr [rbp-8] = rax 레지스터에 [rbp-0x8] 영역에 저장된 값을 저장한다.

- rbp-8 영역에 저장된 값: 0x347360dd65e9dd00

ni

xor rax, qword ptr fs:[0x28] = rax 레지스터에 저장된 값과 fs:0x28 레지스터에 저장된 값을 xor 연산한다.

ni

je main+78 = rax 레지스터의 값이 0과 같으면 main+78 영역으로 이동한다

ni

프로그램이 정상적으로 종료된다.

(2) canary 값 덮어쓰기

breakpoint를 설정하고 처음 r 실행하는 것 까지는 위 (1)과 동일하다. 또한 사용자의 입력 값이 저장되는 위치와 canary의 위치는 (1)과 동일하다.

(1)과 달리 canary를 덮어쓰기 위해 "A"*40 + "B"*8 를 입력한다. ni 실행 전 rbp위치에서의 값을 읽는다.

사용자의 입력값으로 인해 canary의 값이 0x4242424242424242으로 바뀌었다.

c

rax 레지스터에 rbp(7fffffffde00)-0x8 영역에 저장된 값(0x4242424242424242)을 저장한다.

ni

rax 레지스터에 저장된 값과 fs:0x28 레지스터에 저장된 값을 xor 연산한다.

ni

rax 레지스터의 값이 0이 아닌 0xa4a5ca368213b642이기 때문에 0x400624가 아닌 0x40061f로 이동한다.

따라서 __stack_chk_fail 영역 바이너리 옵션 타입 영역 바이너리 옵션 타입 함수를 호출하게 되면서 "stack smashing detected" 오류 메시지를 출력한다.

SSP (Stack Smashing Protector)

memory corruption 취약점 중 스택 버퍼 오버플로우 취약점을 막기 위해 개발된 보호기법; 스택 버퍼와 스택 프레임 포인터(SFP) 사이에 카나리를 생성해 함수 종료 시점에서 카나리 값의 변조 여부를 검사해 스택이 망가뜨려졌는지 확인한다.

마스터 카나리는 main함수가 호출되기 전에 랜덤으로 생성된 카나리를 스레드 별 전역변수로 사용되는 TLS(Thread Local Storage)에 저장한다.

* TLS영역은 _dl_allocate_tls_sotrage함수에서 __libc_memalign 함수를 호출하여 할당한다. 그리고 tcbhead_t 구조체를 가진다.

security_init 함수는 _dl_setup_stack_chk_guard 함수에서 반환한 랜덤 카나리 값을 설정한다.

THREAD_SET_STACK_GUARD 매크로는 TLS 영역의 header.stack_guard에 카나리의 값을 삽입하는 역할을 한다.

Example (1) -32bit

- 256byte 크기의 배열 buf를 할당하고 read를 통해 입력받는다.

- SSP 보호기법이 적용되어 있고 지역변수(buf)를 사용하기 때문에 main 함수에서 카나리를 삽입하고 검사하는 루틴이 존재한다.

main+20: mov DWORD PTR [ebp-0xc], eax (= eax의 값을 [ebp-0xc]의 주소로 이동)에 breakpoint를 설정하고 실행한다. 즉, eax에 저장된 canary의 값이 ebp-0xc에 저장되므로 rbp-8이 카나리의 위치가 된다. eax 레지스터를 보면 카나리의 값이 0xc104ff00이다.

master32 프로세스의 메모리 맵 중 TLS 영역은 0xf7e01000 ~ 0xf7e02000이고, TLS 영역의 header.stack_guard(0xf7e01714)에 canary가 존재하는 것을 확인할 수 있다. 이는 gs:0x14를 접근함으로써 참조할 수 있다. 따라서, master canary를 공격자가 조작하게 되면 random canary의 값을 몰라도 gs:0x14에 접근해 비교하는 SSP 보호기법을 우회할 수 있게된다.

Example (2)

ssp 기법이 적용되어 있지 않아 canary가 발견되지 않는 no_ssp 바이너리와 ssp 기법을 적용해 canary가 발견되는 ssp 바이너리

SSP 보호기법이 적용된 경우 스택 배열을 사용하는 함수가 있으면 함수의 시작부분과 끝부분에 ssp.c와 같이 stack_guard 체크 코드가 삽입된다. → ssp에서는 함수의 프롤로그와 에필로그 부분에 스택 영역 바이너리 옵션 타입 카나리 검증 루틴이 추가되어 있다.

스택 버퍼 오버플로우 취약점을 트리거해본다.

버퍼의 크기(16)보다 긴 문자열(AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)를 입력

no_ssp 바이너리는 Segmentation fault 에러가 출력되며 프로그램이 비정상 종료되고,

ssp 바이너리는 __stack_chk_fail 함수가 호출되면서 stack smashing detected가 출력되면서 프로그램을 종료한다.

stack canary를 bufferoverflow를 통해 변조했다

Bypassing SSP (1)

SSP 보호기법을 우회하려면 스택 메모리에 존재하는 스택 카나리의 값을 변조시키지 않은 채로 exploit 해야한다.

Canary 발견됨 = SSP 적용되어 있음

- main 함수에서 read(0, buf, 512를 두 번 호출하는데, 이 때 buf의 크기보다 더 큰 크기를 입력받도록 되어 있어 스택 버퍼오버플로우가 두 번 발생한다.

- SSP가 설정되어 있기 때문에, 스택 카나리의 값을 알아내지 못하면 스택 버퍼 오버플로우만으로 exploit할 수 없다.

- printf("%s"): NULL 바이트를 만날 때까지 출력한다. → buf 배열의 끝이 NULL이 아니라면?! buf 배열 밖의 메모리까지 출력할 수 있게된다!

read함수를 호출하는 시점에 breakpoint를 설정하고 esp의 주소를 확인해보면 0xffffcfd4임을 확인할 수 있다. 이 때 example1.c 소스코드를 보면 buf의 크기가 32byte = 0x20이기 때문에 카나리의 주소가 0xffffcff4임을 알 수 있다.

→ '스택카나리+1'부터 'buf'까지의 거리 = 0x21

스택 카나리의 값을 출력하는 leak.py 를 실행한 결과 canary의 값은 0x9166a300이다.

gdb를 통해 give_shell 함수의 주소를 구하면 그 주소값은 0x804854b이고 이 값으로 리턴 주소를 덮어 쉘을 획득해본다.

쉘 획득!

Bypassing SSP (2)

fork 함수: 부모 프로세스의 TLS 영역과 스택 메모리 등을 복제해 자식 프로세스를 생성하는 함수 >> fork 함수를 사용하여 자식 프로세스를 생성할 경우, 보무와 자식 프로세스의 스택 카나리의 값은 동일하다.

△ ssp_server.c fork 함수를 이용한 서버프로그램의 소스코드

- 31377번 포트에 TCP 서버를 연 후 클라이언트의 연결이 들어오면 자식 프로세스를 생성한 후 handler 함수를 호출한다.

- handler 함수: 32byte의 버퍼에 1024byte를 입력받기 때문에 Buffer Overflow가 발생한다.

- SSP 보호기법이 적용되어있기 때문에 스택 버퍼 오버플로우를 익스플로잇하려면 SSP를 우회해야한다.

- 부모 프로세스: 자식 프로세스의 시그널을 처리하는 루틴이 없다 >> 자식 프로세스에서 SIGSEGV, SIGABRT 예외가 발생해도 종료되지 않는다.

- handler 함수가 정상적으로 리턴된다면 bye 문자열을 출력하고, 자식 프로세스가 SIGABRT 예외로 종료된다면 bye 문자열을 출력하지 않는다.

→ "bye" 문자열이 출력되는지에 따라 스택 카나리 검사를 통과했는지 여부를 확인 가능 + 자식 프로세스와 부모 프로세스의 스택 카나리는 동일 => 브루트 포싱 공격 (brute force attack) 으로 스택 카나의 값을 한 바이트씩 알아낼 수 있다.

△ ssp_server.py : ssp_server의 스택 카나리 값을 알아내고 handler 함수의 리턴 주소를 critical 함수의 주소로 덮어 critical 함수를 호출하여 공격하는 코드

- 스택 카나리의 3byte를 알아내고 payload를 전달함으로 스택 카나리를 알아낸다. 알아낸 스택 카나리를 이용해 handler 함수의 리턴 주소를 critical 함수의 주소로 덮는다.

- client_fd = u32(s.recv(4)): 클라이언트의 소켓 파일 디스크립터 client_fd를 알아내고 critical 함수의 인자로 전달한다.

자바 메모리 관리 - 가비지 컬렉션

C 나 C++ 에서는 OS 레벨의 메모리에 직접 접근하기 때문에 free() 라는 메소드를 호출하여 할당받았던 메모리를 명시적으로 해제해주어야 한다. 그렇지 않으면 memory leak 이 발생하게 되고, 현재 실행중인 프로그램에서 memory leak 이 발생하면 다른 프로그램에도 영향을 끼칠 수 있다.

반면, 자바는 OS 의 메모리 영역에 직접적으로 접근하지 않고 JVM 이라는 가상머신을 이용해서 간접적으로 접근한다. JVM 은 C 로 쓰여진 또 다른 프로그램인데, 오브젝트가 필요해지지 않는 시점에서 알아서 free() 를 수행하여 메모리를 확보한다. 웹 애플리케이션을 만들 때 모든 것을 다 직접 개발하여 쓰기보다 검증된 라이브러리나 프레임워크를 이용하는 것이 더 안전하고 편리한 것 처럼, 메모리 관리라는 까다로운 부분을 자바 가상머신에 모두 맡겨버리는 것이다.

프로그램 실행시 JVM 옵션을 주어서 OS에 요청한 사이즈 만큼의 메모리를 할당 받아서 실행하게된다. 할당받은 이상의 메모리를 사용하게 되면 에러가 나면서 자동으로 프로그램이 종료된다. 그러므로 현재 프로세스에서 메모리 누수가 발생하더라도 현재 실행중인 것만 죽고, 다른 것에는 영향을 주지 않는다.

이렇게 자바는 가상머신을 사용함으로써 (운영체제로 부터 독립적이라는 장점 외에도) OS 레벨에서의 memory leak 은 불가능하게 된다는 장점이 있다.

자바가 메모리 누수현상을 방지하는 또 다른 방법이 가비지 컬렉션이다.

Garbage Collection

Garbage collection was invented by John McCarthy around 1959 to simplify manual memory management in Lisp. [Wiki] Garbage collection (computer science)

가비지 컬렉션이라는 개념은 자바에서 처음 사용된 것이 아니다. LISP 라는 언어에서 처음 도입된 개념이다. 하지만, 자바가 가비지 컬렉션이란 개념을 더욱 대중화 시킨데 기여한 부분은 있다.

프로그래머는 힙을 사용할 수 있는 만큼 자유롭게 사용하고, 더 이상 사용되지 않는 오브젝트들은 가비지 컬렉션을 담당하는 프로세스가 자동으로 메모리에서 제거하도록 하는 것이 가비지 컬렉션의 기본 개념이다.

자바는 가비지 컬렉션에 아주 단순한 규칙을 적용한다.

Heap 영역의 오브젝트 중 stack 에서 도달 불가능한 (Unreachable) 오브젝트들은 가비지 컬렉션의 대상이 된다.

무슨말인지 정확히 이해되지 않는다면, Java Memory Management - Stack and Heap 를 먼저 읽는 것을 추천한다.

Garbage Collection 살짝 겉핥아보기

이제 간단한 코드를 살펴보면서 garbage collection 이 뭔지 살짝만 알아보자.

구문이 실행된 뒤 스택과 힙은 아래와 같다.

stack and heap

문자열 더하기 연산이 수행되는 과정에서, (String 은 불변객체이므로) 기존에 있던 "https://" 스트링에 "yaboong.github.io" 를 덧붙이는 것이 아니라, 문자열에 대한 더하기 연산이 수행된 결과가 새롭게 heap 영역에 할당된다. 그 결과를 영역 바이너리 옵션 타입 그림으로 표현하면 아래와 같다.

stack and heap

Stack 에는 새로운 변수가 할당되지 않는다. 문자열 더하기 연산의 결과인 "https://yaboong.github.io" 가 새롭게 heap 영역에 생성되고, 기존에 "https://" 를 레퍼런스 하고 있던 url 변수는 새롭게 생성된 문자열을 레퍼런스 하게 된다.

기존의 "https://" 라는 문자열을 레퍼런스 하고 있는 변수는 아무것도 없으므로 Unreachable 오브젝트가 된다.

JVM 의 Garbage Collector 는 Unreachable Object 를 우선적으로 메모리에서 제거하여 메모리 공간을 확보한다. Unreachable Object 란 Stack 에서 도달할 수 없는 Heap 영역의 객체를 말하는데, 지금의 예제에서 "https://" 문자열과 같은 경우가 되겠다. 아주 간단하게 이야기해서 이런 경우에 Garbage Collection 이 일어나면 Unreachable 오브젝트들은 메모리에서 제거된다.

Garbage Collection 과정은 Mark and Sweep 이라고도 한다. JVM의 Garbage Collector 가 스택의 모든 변수를 스캔하면서 각각 어떤 오브젝트를 레퍼런스 하고 있는지 찾는과정이 Mark 다. Reachable 오브젝트가 레퍼런스하고 있는 오브젝트 또한 marking 한다. 첫번째 단계인 marking 작업을 위해 모든 스레드는 중단되는데 이를 stop the world 라고 부르기도 한다. (System.gc() 를 생각없이 호출하면 안되는 이유이기도 하다)

그리고 나서 mark 되어있지 않은 모든 오브젝트들을 힙에서 제거하는 과정이 Sweep 이다.

Garbage Collection 이라고 하면 garbage 들을 수집할 것 같지만 실제로는 garbage 를 수집하여 제거하는 것이 아니라, garbage 가 아닌 것을 따로 mark 하고 그 외의 것은 모두 지우는 것이다. 만약 힙에 garbage 만 가득하다면 제거 과정은 즉각적으로 이루어진다.

Garbage Collection 이 일어난 후의 메모리 상태는 아래와 같을 것이다.

stack and heap

System.gc()

System.gc() 를 호출하여 명시적으로 가비지 컬렉션이 일어나도록 코드를 삽입할 수 있지만, 모든 스레드가 중단되기 때문에 코드단에서 호출하는 짓은 하면 안된다. 자바 도큐먼트를 보면 gc() 메소드에 대한 설명은 아래와 같다.

System.gc()

https://docs.oracle.com/javase/8/docs/api/

System.gc() 호출하는게 하면 안되는 짓이라는데 한번 해보자.

아무것도 하지 않고 시간만 측정하는 코드다.

내 피씨에서는 275ns 가 나온다. 275 나노초면 0.000000275초의 시간이다. 아무것도 하는게 없는 코드니까 당연히 엄청 빠르다. 이제 startTime, endTime 사이에 System.gc() 를 심어보자.

  • 가비지 컬렉션이 수행되는지 보려면 jvm 옵션으로 -verbose:gc 를 주면 된다.
  • 어떤 가비지 컬렉터를 사용하고 있는지 보기위해 jvm 옵션으로 -XX:+PrintCommandLineFlags 도 주고 시작하자.
  • IntelliJ 라면 Edit Configurations -> VM options -> -verbose:gc -XX:+PrintCommandLineFlags 를 입력하면 된다.

첫번째 라인은 -XX:+PrintCommandLineFlag 에 의해 출력된 값들이고, 두번째 세번째 라인은 -verbose:gc 옵션을 주어 가비지 컬렉션이 일어날때 자동출력된 부분이다.

첫번째 라인의 마지막을 보면 -XX:+UseParallelGC 옵션이 있는데 ParallelGC 라는 가비지 컬렉터를 사용하고 있다는 것이다.

어쨌든 실행시간에 대한 결과를 보면 6959381 나노초가 나온다. 0.006959381 초의 시간이다. JVM 옵션을 모두 제거하고 돌려도 비슷한 시간이 나온다. System.gc() 를 호출하기 전에 275 나노초, 호출하면 6959381 나노초. 아무역할도 하지 않는 코드로 단순히 산술적 비교를 하는 것이 무의미할 수도 있지만, 호출하면 안될 것 같다는 위험성은 느껴진다.

System.gc() 소스까보기

System.gc() 를 타고 들어가면 아래와 같이 생겼다.

Runtime.getRuntime().gc() 를 타고 들어가면,

native 라는 키워드가 붙은 메소드는 자바가 아닌 다른 프로그래밍 언어로 쓰여진 메소드를 말한다. JVM 이 C 언어 로 쓰여졌으니까 아마 C 언어로 작성되었을 것 같다. 어쨌든 자바의 영역을 벗어나니까 일단 넘어가자.

Garbage Collection 코드로 확인하기

1. 프로그램이 메모리 부족으로 죽는 경우

OutOfMemoryError 를 빨리내고, GC 를 확인하기 위해서 jvm 옵션으로 -Xmx16m -verbose:gc 를 주고 시작하자. -Xmx 는 힙영역의 최대 사이즈 를 설정하는 것이다. 16MB 로 설정했다.

실행결과를 보면 가비지 컬렉션 작업을 몇번 반복하다가 결국 OutOfMemoryError 를 뱉으며 프로그램이 죽어버린다. 위에서, 가비지 컬렉션의 대상이 되는 오브젝트는 Unreachable 오브젝트라고 했다. 그런데 무한루프의 외부에서 선언한 ArrayList 는 무한루프가 도는 동안에도 계속해서 Reachable 하기 때문에 (레퍼런스가 끊이지 않기 때문에), 가비지 컬렉션 작업이 진행되어도 힙에 모든 데이터가 계속 남아있게 된다.

즉, 무한루프를 돌기 때문에 프로그램이 죽은 것이 아니라, ( Unreachable 오브젝트가 없으므로) 가비지 컬렉션이 일어나도 모든 오브젝트가 살아있기 때문에 OutOfMemoryError 가 발생한 것이다.

똑같이 무한루프를 돌지만, Unreachable 오브젝트를 만들어 내는 코드를 살펴보자.

2. 가비지 컬렉터가 열일하여 프로그램이 죽지 않는 경우

JVM 옵션으로 똑같이 -Xmx16m -verbose:gc 를 주고 실행했다.

Thread.sleep() 하는 부분에서 li 변수에 새로운 ArrayList 를 생성하도록 해보자. 그리고 몇번째 루프에서 가비지 컬렉션이 수행되는지 확인하기 위해 프린트도 하나 찍어보자. 무한루프를 돌면서 중간중간에 List 를 가비지가 되도록 만들어서 가비지 컬렉션이 수행되면 프로그램은 죽지않고 계속해서 돌아갈 것이다. 코드는 아래와 같다.

실행결과는 아래와 같다. 루프 횟수는 . 으로 표시했다.

if (i % 100 == 0) 구문으로 100 번째 단위로 루프를 돌때마다 (새로운 리스트를 할당하여) 기존에 있던 리스트를 가비지로 만들어주니 프로그램이 죽지 않고 계속 돌아가는 것을 보면, 가비지 컬렉터가 열일하고 있다는 것을 알 수 있다.

첫 번째 코드예제에서, 스택에 한개의 리스트 레퍼런스 변수를 두고 같은 리스트에 계속해서 데이터를 추가하면, 가비지 컬렉션이 이루어져도 가비지로 분류되는 Unreachable 오브젝트가 없기 때문에 프로그램이 죽는 것을 확인했다.

두 번째 코드예제에서는, 똑같이 스택에 한개의 리스트 레퍼런스 변수를 두더라도, 주기적으로 새로운 리스트를 생성해서 새롭게 생성한 리스트를 레퍼런스 하도록 만들었다. 그 결과, Unreachable 오브젝트 가 되어버린 기존 리스트들을 가비지 컬렉터가 메모리에서 제거함으로써 프로그램이 죽지않고 돌아가는 것을 확인했다.

VisualVM 으로 모니터링하기

시각화된 그래프를 보면서 프로그램을 모니터링 할 수 있다. 본인의 java 설치경로 (아마 $JAVA_HOME) 의 bin 디렉토리로 가서 jvisualvm 을 실행시킨다.

힙의 세부적인 모니터링을 위해 VisualGC 라는 플러그인을 설치할 것인데 이렇게 실행하니까 잘 안돼서 그냥 툴을 다운 받았다. [Go to VisualVM Download Page]

Java 9 부터는 Graal Visual VM 으로 바뀌었다고 한다. 이 글은 Java 8 을 기준으로 작성되었으므로 Java 9 을 사용한다면 Graal Visual VM 을 사용할 수 있다.

Visual VM

Visual VM 을 실행하면 위와같은 화면을 볼 수 있다. 왼쪽에 있는 프로세스들에 대한 모니터링이 가능하다. 하지만 지금은 가비지 컬렉션이 어떻게 이루어지는지 보기 위해 heap 영역을 좀더 세부적으로 모니터링 하고 싶다. 그러기 위해서 VisualGC 라는 플러그인이 필요한데, 상단 메뉴에서 Tool > Plugins > Available Plugins 로 가서 Visual GC 를 체크한 후 Install 을 클릭한다.

Visual GC Plugin

Visual GC 플러그인을 설치하면 힙의 각 영역별로 세부적인 모니터링이 가능하다.

메모리 구성 - Metaspace & Heap

Visual VM 과 Visual GC 를 이용하여 프로그램을 실행했을 때 메모리 변화에 대한 모니터링을 해보자.

1. Metaspace

먼저 metaspace 에 대해 알아보자. 자바 8 에 적용된 변화로 람다, 스트림, 인터페이스의 default 지시자가 대표적이다. 하지만, 메모리의 관점에서 가장 큰 변화로는 PermGen 이 사라지고 Metaspace 가 이를 대체하게 되었다는 것이다.

PermGen 은 자바 7까지 클래스의 메타데이터를 저장하던 영역이었고 Heap 의 일부였다. 주요 내용만 뽑아보면,

  • Permanent Generation은 힙 메모리 영역중에 하나로 자바 애플리케이션을 실행할때 클래스의 메타데이터를 저장하는 영역이다.(Java 7기준)
  • 아래와 같은 것들이 Java Heap 이나 native heap 영역으로 이동했다.
    • Symbols -> native heap
    • Interned String -> Java Heap
    • Class statics -> Java Heap

    자바 8 부터 클래스들은 모두 힙이 아닌 네이티브 메모리를 사용하는 Metaspace 에 할당된다고 하는데, 한번 확인해보자.

    위 코드는 metaspace 를 사용하게 될 class 들을 런타임시에 생성한다. 코드를 실행하기 전에 javassist 라이브러리를 추가하고, 아래코드를 실행시킨 뒤 VisualVM 에서 모니터링 해보자.
    Metaspace 를 제한하기 위해 vm 옵션으로 -XX:MaxMetaspaceSize=128m 을 주고 실행시킨다. 최대 Metaspace 의 크기를 128 MB 로 제한하는 옵션이다.

    VisualVM 의 VisualGC 탭으로 들어가면 아래와 같은 화면을 볼 수 있다. java.lang.OutOfMemoryError: Metaspace 에러로 인해 프로그램이 죽은 상태의 캡처본이다.

    java.lang.OutOfMemoryError: Metaspace

    Metaspace 의 크기가 128MB 에 도달하면 OutOfMemoryError: Metaspace 오류를 뱉으며 죽는 것을 확인할 수 있다.

    서론이 너무 길었는데, 어쨌든 Metaspace 는 Heap 과는 상관없는 네이티브 메모리 영역이다.

    Metaspace 를 제외한, Heap 에 해당하는 Old, Eden, S0, S1 에 대해서 알아보자.

    2. Heap - Old & Young (Eden, Survivor)

    위 모니터링 화면에서 Spaces 부분을 보면 다섯개의 영역으로 나누어져 있는 것을 볼 수 있다. Metaspace, Old, Eden, S0, S1 총 다섯개 영역이다.

    http://www.waitingforcode.com/off-heap/on-heap-off-heap-storage/read

    Heap 은 Young Generation, Old Generation 으로 크게 두개의 영역으로 나누어 지고, Young Generation 은 또다시 Eden, Survivor Space 0, 1 로 세분화 되어진다. S0, S1 으로 표시되는 영역이 Survivor Space 0, 1 이다. 각 영역의 역할은 가비지 컬렉션 프로세스를 알면 알 수 있다.

    가비지 컬렉션 프로세스

    1. 새로운 오브젝트는 Eden 영역에 할당된다. 두개의 Survivor Space 는 비워진 상태로 시작한다.
    2. Eden 영역이 가득차면, MinorGC 가 발생한다.
    3. MinorGC 가 발생하면, Reachable 오브젝트들은 S0 으로 옮겨진다. Unreachable 오브젝트들은 Eden 영역이 클리어 될때 함께 메모리에서 사라진다.
    4. 다음 MinorGC 가 발생할때, Eden 영역에는 3번과 같은 과정이 발생한다. Unreachable 오브젝트들은 지워지고, Reachable 오브젝트들은 Survivor Space 로 이동한다. 기존에 S0 에 있었던 Reachable 오브젝트들은 S1 으로 옮겨지는데, 이때, age 값이 증가되어 옮겨진다. 살아남은 모든 오브젝트들이 S1 으로 모두 옮겨지면, S0 와 Eden 은 클리어 된다. Survivor Space 에서 Survivor Space 로의 이동은 이동할때마다 age 값이 증가한다.
    5. 다음 MinorGC 가 발생하면, 4번 과정이 반복되는데, S1 이 가득차 있었으므로 S1 에서 살아남은 오브젝트들은 S0 로 옮겨지면서 Eden 과 S1 은 클리어 된다. 이때에도, age 값이 증가되어 옮겨진다. Survivor Space 에서 Survivor Space 로의 이동은 이동할때마다 age 값이 증가한다.
    6. Young Generation 에서 계속해서 살아남으며 age 값이 증가하는 오브젝트들은 age 값이 특정값 이상이 되면 Old Generation 으로 옮겨지는데 이 단계를 Promotion 이라고 한다.
    7. MinorGC 가 계속해서 반복되면, Promotion 작업도 꾸준히 발생하게 된다.
    8. Promotion 작업이 계속해서 반복되면서 Old Generation 이 가득차게 되면 MajorGC 가 발생하게 된다.

    위 과정의 반복이 가비지 컬렉션이다.

    • MinorGC : Young Generation 에서 발생하는 GC
    • MajorGC : Old Generation (Tenured Space) 에서 발생하는 GC
    • FullGC : Heap 전체를 clear 하는 작업 (Young/Old 공간 모두)

    Garbage Collection 눈으로 확인하기

    1. 프로그램이 메모리 부족으로 죽는 경우

    실행시 VisualVM 으로 모니터링 한 화면을 녹화해 보았다. (유튜브 영상 전체화면 기능이 이상하게 먹힙니다… 유튜브 페이지로 가서 전체화면으로 봐주세요… )

    VisualVM 그래프를 보면, Eden 영역이 활발하게 생성되는 것이 보인다. 또한, Eden 이 가득차면 Survivor Space 로 이동하고, 기존에 Survivor Space 에서 오랫동안 살아남은 오브젝트들이 Old Generation 으로 이동하게 되는 것도 보인다. 심지어 Eden 이 차기도 전에 Old Generation 으로 이동하는 경우도 보인다. 실행 로그를 보면 FullGC 가 발생하는 것도 볼 수 있는데, FullGC 가 실행되었음에도 불구하고 힙에 더 이상 할당할 수 있는 공간이 없어서 OutOfMemoryError 를 뱉으면서 죽는다.

    2. 가비지 컬렉터가 열일하여 프로그램이 죽지 않는 경우

    아래 영상 역시 VisualVM 으로 모니터링 한 화면을 녹화한 것이다. (유튜브 영상 전체화면 기능이 이상하게 먹힙니다… 유튜브 페이지로 가서 전체화면으로 봐주세요… )

    VisualVM 그래프를 보면, 첫 번째 경우와 동일하게 Eden 은 활발하게 움직이는 것을 볼 수 있다. 또한, 처음에는 Eden 에서 Survivor Space 로 이동하는 오브젝트가 많지만, 시간이 지나면서 살아남는 오브젝트들이 점점 줄어드는 것이 보인다. 이는 생성되는 오브젝트들의 생명주기가 굉장히 짧은 것을 의미한다. Survivor Space 에서 Old Generation 으로의 Promotion 과정도 미미하게 발생하지만 첫 번째 경우보다 Old Generation 이 증가하는 속도는 굉장히 더딘 것을 확인할 수 있다.

    Garbage Collector 종류 겉핥기

    이제 가비지 컬렉션은 어느정도 알게 된 것 같다. 그러면 가비지 컬렉션을 담당하는 가비지 컬렉터에는 어떤 것들이 있는지 간략하게 살펴보자.

    Serial GC

    -XX:+UseSerialGC 옵션을 줘서 사용할 수 있는 Serial GC 는 Java SE 5, 6 에서 사용되는 디폴트 가비지 컬렉터이다.

    • MinorGC, MajorGC 모두 순차적으로 시행된다.
    • Mark-Compact collection method 를 영역 바이너리 옵션 타입 사용한다.

    Mark-Compact collection method 란, 새로운 메모리 할당을 빠르게 하기 위해서 기존의 메모리에 있던 오브젝트들을 힙의 시작위치로 옮겨 놓는 방법이다. 창고에서 필요없는 물건들을 버린 후, 창고에 물건을 차곡차곡 쌓기위해 창고안을 정리하는 것이라 생각할 수 있다. 아래 그림을 참고하면 이해가 쉽다.

    http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

    Parallel GC

    -XX:+UseParallelGC 옵션으로 사용 가능한 Parallel 가비지 컬렉터는 young generation 에 대한 가비지 컬렉션 수행시 멀티스레드를 사용한다. 멀티스레딩을 할 수 있는 ParallelGC 를 사용하도록 옵션을 주었더라도, 호스트 머신이 싱글 CPU 라면 디폴트 가비지 컬렉터(Serial GC)가 영역 바이너리 옵션 타입 사용된다. 하지만, 호스트의 CPU 가 두개 이상이라면 young generation 의 가비지 컬렉션 시간을 줄일 수 있다.

    가비지 컬렉터 스레드 개수는 디폴트로 CPU 개수만큼이 할당되는데 -XX:ParallelGCThread= 옵션으로 조절가능하다. 또한, -XX:+UseParallelOldGC 옵션을 사용한다면, old generation 의 가비지 컬렉션에서도 멀티스레딩을 활용할 수 있다.

    Concurrent Mark Sweep (CMS) Collector

    Concurrent Low Pause Collector 라고도 불리는 CMS 컬렉터는 -XX:+UseConcMarkSweepGC 옵션으로 사용할 수 있다. 대부분의 가비지 컬렉션 작업을 애플리케이션 스레드와 동시에 수행함으로써 가비지 컬렉션으로 인한 stop-the-world 시간을 최소화하는 GC이다.

    CMS 컬렉터는 young generation 에 대한 가비지 컬렉션시 Parallel GC 와 같은 알고리즘을 사용하는데, -XX:ParallelCMSThreads= 옵션으로 스레드 개수를 설정할 수 있다.

    일반적으로 CMS 컬렉터는 살아있는 오브젝트들에 대한 compact 작업을 수행하지 않으므로, 메모리의 파편화(Fragmentation) 가 문제가 된다면 더 큰 힙사이즈를 할당해야 한다.

    G1 Garbage Collector

    Garbage First 라는 의미의 G1 가비지 컬렉터는 Java 7 부터 사용가능하며, 장기적으로 CMS 컬렉터를 대체하기 위해 만들어졌다. -XX:+UseG1GC 옵션으로 사용가능하다. G1 가비지 컬렉터는 이전까지 이야기한 것들과는 다른 방식으로 동작한다. G1 GC 에 대한 자세한 내용은 [Oracle] Getting Started with the G1 Garbage Collector 를 참고하기 바란다.

    벼르고 벼르고 벼르고 벼르던 가비지 컬렉션에 대한 글을 드디어 마무리했다.

    아래 참고한 자료를 보면 알 수 있겠지만, 가비지 컬렉션을 공부하기 위해 여기저기 정보를 열심히 뒤졌다. 뒤지다 보니까 가비지 컬렉션에 대한 거의 모든 블로그나 강의 내용들이 [Oracle] Java Garbage Collection Basics 이걸 기반으로 작성된 것 같다.

    데이터 타입¶

    수치형 데이터 타입은 정확한(exact) 타입과 근사치(approximate) 타입으로 구분된다. 정확한 수치형 데이터 타입(SMALLINT, INT, BIGINT, NUMERIC)은 정확하고 일관된 값을 가져야 하는 경우에 사용된다. 근사치 수치형 데이터 타입(FLOAT, DOUBLE)은 리터럴 값이 같아도 시스템에 따라 다르게 해석될 수 있으므로 주의한다.

    CUBRID는 수치형 데이터 타입에 대해 UNSIGNED 타입을 지원하지 않는다.

    위의 표에서 두 가지 이름으로 표기한 타입들은 동일하지만, 테이블 생성 후 SHOW COLUMNS 문으로 타입의 이름을 확인할 때에는 항상 위 단어로 표기된다. 예를 들어, 테이블을 생성할 때에는 SHORT, SMALLINT 둘 다 쓸 수 있으며, SHOW COLUMNS 문으로 타입의 이름을 확인할 때에는 항상 SHORT 로 표기된다.

    정밀도와 스케일(Precision and Scaling)

    숫자 데이터 타입의 정밀도(precision)는 그 값이 유지할 수 있는 유효한 자릿수로 정의된다. 이는 정확한 수치형이든 근사치 수치형이든 마찬가지이다.

    스케일(scale)은 소수점 이하의 자릿수를 나타내는데, 정확한 수치형에서만 의미가 있다. 정확한 수치형으로 선언된 속성은 항상 고정된 정밀도와 스케일을 갖게 된다. NUMERIC (또는 DECIMAL) 데이터 타입은 항상 최소한 한 자리의 정밀도를 갖는다. 스케일의 범위는 0과 선언된 정밀도 사이여야 한다. 스케일이 정밀도보다 클 수는 없다. INTEGERSMALLINT, BIGINT 데이터 타입에서는 스케일은 0이고(즉, 소수점 이하가 없음), 정밀도는 시스템에 의해 고정된다.

    수치형 리터럴(Numeric Literals)

    수치형 값을 입력하기 위해서는 특별한 기호가 사용될 수 있는데, 플러스(+)는 양수를, 마이너스(-)는 음수를 나타내는 데 사용한다. 과학용 표기법이 사용될 수도 있다. 화폐 값을 표현하기 위하여 시스템에 지정된 통화 기호를 사용할 수도 있다. 수치형 리터럴로 표현 가능한 최대 정밀도는 255이다.

    수치형 변환(Numeric Coercions)

    모든 수치형 데이터 타입은 상호 비교 가능하고, 이를 위해 서로 공통된 수치형 데이터 타입으로 자동 변환이 이루어진다. 명시적인 변환은 CAST 연산자를 이용해야 한다. 서로 다른 수치형 데이터가 서로 정렬되거나, 수식에서 계산될 때에는 시스템에 의하여 자동으로 변환된다. 예를 들어, FLOAT 타입의 속성 값과 INTEGER 타입의 속성 값을 더하게 되면, 시스템이 자동적으로 INTEGER 속성 값을 가장 근사한 FLOAT 값으로 변환한 후 덧셈을 수행한다.

    다음은 FLOAT 타입 값과 INTEGER 타입 값을 더하는 경우 FLOAT 타입 값을 출력하는 예이다.

    다음은 두 개의 정수 값을 더하는 경우 결과 값도 INTEGER 타입이 되기 때문에 오버플로우(overflow) 에러가 발생하는 예이다.

    위와 같은 경우 어느 한 쪽의 타입을 BIGINT로 명시하면, BIGINT로 결과 값을 결정하고, 정상적인 결과를 출력한다.

    Warning

    CUBRID 2008 R2.0 미만 버전에서는 입력된 상수가 INTEGER 범위를 넘어서면 NUMERIC으로 처리되었으나, CUBRID 2008 R2.0 이상 버전에서는 BIGINT로 처리된다.

    INT, INTEGER¶

    INTEGER 데이터 타입은 정수 표현을 위해 사용하며, 표현할 수 있는 값의 범위는 -2,147,483,648에서 +2,147,483,647이다. 작은 정수를 표현하기 위해 SMALLINT를 사용하거나, 큰 정수를 표현하기 위해 BIGINT를 사용할 수 있다.

    • INTEGERINT는 같은 의미로 사용된다.
    • INT 타입에 실수가 입력되면, 소수점 아래 숫자가 반올림되어 정수값이 저장된다.
    • 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.

    SHORT, SMALLINT¶

    SMALLINT 데이터 타입은 작은 정수 표현을 위해 사용되며, 표현할 수 있는 값의 범위는 -32,768에서 +32,767이다.

    • SMALLINTSHORT는 같은 의미로 사용된다.
    • SMALLINT 타입에 실수가 입력되면, 소수점 아래 숫자가 반올림되어 정수값이 저장된다.
    • 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.

    BIGINT¶

    BIGINT 데이터 타입은 큰 정수 표현을 위해 사용되며, 표현할 수 있는 값의 범위는 -9,223,372,036,854,775,808에서 9,223,372,036,854,775,807이다.

    BIGINT 타입에 실수가 입력되면, 소수점 아래 숫자가 반올림되어 정수값이 저장된다.

    정밀도와 표현할 수 있는 범위를 기준으로는 다음과 같이 정렬할 수 있다.

    SMALLINTINTEGERBIGINTNUMERIC

    이 타입의 칼럼에 DEFAULT 속성이 지정될 수 영역 바이너리 옵션 타입 있다.

    NUMERIC, DECIMAL¶

    NUMERIC 또는 DECIMAL 데이터 타입은 고정 소수점 숫자를 표현하기 위해 사용되며, 다음과 같이 전체 자리 수(정밀도)와 소수점 아래 자릿수(스케일)을 옵션으로 지정하여 정의할 수 있다. 정밀도 p의 최소값은 1이고 최대값은 38이며, 정밀도 p가 생략되면 기본값은 15이므로, 정수부가 15자리를 초과하는 데이터를 입력할 수 없다. 또한, 스케일 s가 생략되면 스케일의 기본값은 0이므로 소수점 아래 첫째 자리에서 반올림한 정수를 반환한다.

    • 정밀도는 반드시 스케일 이상이어야 한다.
    • 정밀도는 (데이터의 정수부 자리 수 + 스케일) 이상이 되도록 지정한다.
    • NUMERICDECIMAL, 그리고 DEC는 같은 의미로 사용된다.
    • NUMERIC 타입끼리 연산한 결과 값의 정밀도와 스케일이 어떻게 달라지는지 확인하려면 수치형 데이터 타입의 산술 연산과 타입 변환 을 참고한다.
    • 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.

    FLOAT, REAL¶

    FLOAT (또는 REAL) 데이터 타입은 부동 소수점 숫자를 표현하기 위해 사용된다.

    정규 값(normalized value)으로 표현할 수 있는 값의 범위는 -3.402823466E+38 에서 -1.175494351E-38, 0, 그리고 +1.175494351E-38 에서+3.402823466E+38이며, 이 범위를 벗어나서 0에 가까운 값은 비정규 값(denormalized value)으로 표현한다. 이는 ANSI/IEEE 754-1985 표준을 준수한다.

    정밀도 p의 최소값은 1이고 최대값은 38이며, 정밀도 p가 생략되거나 7 이하로 지정되면 단일 정밀도(single-precision, 7자리의 유효 숫자)로 표현된다. 만약 정밀도 p가 7보다 크고 38 이하이면 이중 정밀도(double-precision, 15자리의 유효 숫자)로 표현되며, DOUBLE 데이터 타입으로 변환된다.

    FLOAT 데이터 타입은 7자리의 유효 자릿수를 넘는 입력 값에 대해 근사치를 저장하는 타입이므로 유효 자릿수를 넘어서는 정확한 값을 저장하려면 사용하지 않도록 주의한다.

    • FLOAT 타입의 유효 자리 수는 7이다.
    • FLOAT 타입은 근사치 데이터를 저장하므로 데이터 비교 시 주의해야 한다.
    • FLOATREAL은 같은 의미로 사용된다.
    • 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.

    DOUBLE, DOUBLE PRECISION¶

    DOUBLE 데이터 타입은 부동 소수점 숫자를 표현하기 위해 사용된다.

    정규 값(normalized value)으로 표현할 수 있는 값의 범위는 -1.7976931348623157E+308에서 -2.2250738585072014E-308, 0, 그리고 2.2250738585072014E-308에서 1.7976931348623157E+308이며, 이 범위를 벗어나서 0에 가까운 값은 비정규 값(denormalized value)으로 표현한다. 이는 ANSI/IEEE 754-1985 표준을 준수한다.

    정밀도를 지정할 수 없으며, 이 타입이 지정된 데이터는 이중 정밀도(double-precision, 15자리의 유효 숫자)로 표현된다.

    DOUBLE 데이터 타입은 15자리의 유효 자릿수를 넘는 입력 값에 대해 근사치를 저장하는 타입이므로 유효 자릿수를 넘어서는 정확한 값을 지정할 때에는 사용하지 않도록 주의한다.

    • DOUBLE의 유효 자리 수는 15자리이다.
    • DOUBLE 타입은 근사치 데이터를 저장하므로 데이터 비교 시 주의해야 한다.
    • DOUBLEDOUBLE PRECISION은 같은 의미로 사용된다.
    • 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.

    MONETARY 타입은 제거될 예정이며(deprecated), 더 이상 사용을 권장하지 않는다.

    날짜/시간 데이터 타입¶

    날짜/시간 데이터 타입은 날짜, 시간 혹은 이 두 가지를 모두 표현할 때 사용하는 데이터 타입으로 다음과 같은 데이터 타입을 지원한다.

    타입 bytes 최소값 최대값 비고
    DATE 4 0001년 1월 1일 9999년 12월 31일 예외적으로 DATE '0000-00-00'을 입력할 수 있다.
    TIME 4 00시 00분 00초 23시 59분 59초
    TIMESTAMP 4 1970년 1월 1일 0시 0분 1초(GMT) 1970년 1월 1일 9시 0분 1초(KST) 2038년 1월 19일 3시 14분 7초(GMT) 2038년 1월 19일 12시 14분 7초(KST) 예외적으로 TIMESTAMP '0000-00-00 00:00:00'을 입력할 수 있다.
    DATETIME 8 0001년 1월 1일 0시 0분 0.000초 9999년 12월 31일 23시 59분 59.999초 예외적으로 DATETIME '0000-00-00 00:00:00'을 입력할 수 있다.

    범위와 해상도(Range and Resolution)

    • 시간 값의 표현은 기본적으로 24시간 시스템에 의하여 그 범위가 결정된다. 날짜는 그레고리력(Gregorian calendar)을 따른다. 이 두 제약 사항을 벗어나는 값이 날짜나 시간으로 입력되면 오류가 발생한다.
    • DATE 중 연도의 범위는 0001~9999 AD이다.
    • CUBRID 2008 R3.0 버전부터는 연도를 두 자리만 표기하면, 00~69는 2000~2069로 변환되고, 70~99는 1970~1999로 변환된다. R3.0 미만 버전에서는 01~99까지의 두 자리 연도를 표기하면, 각각 0001~0099로 변환된다.
    • TIMESTAMP 의 범위는 GMT로 1970년 1월 1일 0시 0분 1초부터 2038년 1월 19일 03시 14분 07초까지이다. KST (GMT+9)로는 1970년 1월 1일 9시 0분 1초부터 2038년 1월 19일 12시 14분 07초까지 저장할 수 있다. GMT로 timestamp'1970-01-01 00:00:00'은 timestamp'0000-00-00 00:00:00'와 같다.
    • 날짜, 시간, 타임스탬프와 관련된 연산은 시스템의 반올림 시스템에 따라 결과가 달라질 수 있다. 이러한 경우, 시간과 타임스탬프는 가장 근접한 초를 최소 해상도로, 날짜는 영역 바이너리 옵션 타입 가장 근접한 날짜를 최소 해상도로 하여 결정된다.

    변환(Coercion)

    날짜/시간 데이터 타입의 값은 서로 똑같은 항목을 가지고 있는 경우에만 CAST 연산자를 이용한 명시적인 변환이 가능하며, 묵시적 변환은 묵시적 타입 변환 을 참고한다. 아래의 표는 명시적 변환이 가능한 타입을 설명한다. 날짜/시간 데이터 타입 간 산술 연산에 대한 내용은 날짜/시간 데이터 타입의 산술 연산과 타입 변환 을 참고한다.

    명시적 변환

    FROM \ TO DATE TIME DATETIME TIMESTAMP
    DATE - X O O
    TIME X - X X
    DATETIME O O - O
    TIMESTAMP O O O -

    DATE, DATETIME, TIMESTAMP 타입의 연, 월, 일에는 0을 입력할 수 없으나, 예외적으로 날짜와 시간이 모두 0인 값은 허용한다. 해당 타입의 칼럼에 대한 질의 수행 시 인덱스가 있으면 이 값을 사용할 수 있다는 점에서 NULL 대신 사용하면 유용하다.

    • DATE, DATETIME, TIMESTAMP 타입이 인자인 일부 함수는 인자의 날짜와 시간 값이 모두 0이면 시스템 파라미터 return_null_on_function_errors 의 값에 따라 다른 값을 반환한다. return_null_on_function_errors 가 yes이면 NULL 을 반환하고 no이면 에러를 반환하며, 기본값은 no 이다.
    • DATE, DATETIME, TIMESTAMP 타입을 반환하는 함수들은 날짜와 시간 값이 모두 0인 값을 반환할 수 있지만 JAVA 응용 프로그램에서는 이러한 값을 Date 객체에 저장할 수 없다. 따라서 연결 URL 문자열의 zeroDateTimeBehavior 속성(Property) 설정에 따라서 예외로 처리하거나 NULL을 반환하거나 또는 최소값을 반환한다(이에 관한 자세한 내용은 연결 설정 참고).
    • 시스템 파라미터 intl_date_lang을 설정하면 TO_DATE() , TO_TIIME() , TO_DATETIME() , TO_TIMESTAMP() , DATE_FORMAT() , TIME_FORMAT() , TO_CHAR() , STR_TO_DATE() 함수의 입력 문자열 형식이 해당 로캘의 날짜 형식을 따른다. 자세한 내용은 구문/타입 관련 파라미터 과 각 함수의 설명을 참고한다.

    DATE 데이터 타입은 연도(yyyy), 월(mm), 일(dd)을 표현하며, 지원 범위는 '01/01/0001'에서 '12/31/9999'까지이다. 연도는 생략 가능하며, 생략될 경우 현재 시스템의 연도 값이 자동으로 지정된다. 입력 형식은 다음과 같다.

    • 모든 항목은 정수 형태로 입력되어야 한다.
    • CSQL은 'MM/DD/YYYY' 형식으로 날짜 값을 출력하고, JDBC 응용 프로그램 및 CUBRID 매니저는 'YYYY-MM-DD' 형식으로 날짜 값을 출력한다.
    • 문자열 타입의 데이터를 DATE 타입으로 변환하는 함수는 TO_DATE() 이다.
    • 연, 월, 일에는 0을 입력할 수 없으나 예외적으로 연, 월, 일이 모두 0인 '0000-00-00'은 입력할 수 있다.
    • 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.

    TIME 데이터 타입은 시각(hh), 분(mi), 초(ss) 를 표현하며, 지원 범위는 '00:00:00'에서 '23:59:59'까지이다. 초는 생략 가능하며, 생략될 경우 0초로 지정된다. 입력 형식은 12시간 표기법(AM/PM표기법) 또는 24시간 표기법이 모두 허용되며, 다음과 같이 작성한다.

    • 모든 항목은 정수로 입력되어야 한다.
    • CSQL은 항상 AM/PM 표기법으로 시간 값을 출력하고, JDBC 응용 프로그램 및 CUBRID 매니저는 24시간 표기법으로 시간 값을 출력한다.
    • 24시간 표기법으로 시간 값을 입력할 때에도 AM/PM을 지정할 수 있으며, 이때 시간 값과 지정된 AM 또는 PM이 일치하지 않으면 오류가 발생한다.
    • 모든 시간 값은 데이터베이스에는 24시간 표기법으로 저장된다.
    • 문자열 타입의 데이터를 TIME 타입으로 변환하는 함수는 TO_TIME() 이다.
    • 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.

    TIMESTAMP¶

    TIMESTAMP 데이터 타입은 날짜(연, 월, 일)와 시간(시, 분, 초)을 결합한 데이터 값을 표현하며, GMT로 '1970-01-01 00:00:01'부터 '2038-01-19 03:14:07'까지 표현할 수 있다. 이 범위를 초과하거나 밀리초 단위의 시간 데이터를 저장하는 경우라면, DATETIME 데이터 타입을 이용할 수 있다. TIMESTAMP 데이터 타입의 입력 형식은 다음과 같다.

    • 모든 항목은 정수로 입력되어야 한다.
    • 연도를 생략하면 기본값으로 현재 연도가 지정되고, 시간 값(시/분/초)를 생략하면 12:00:00 AM으로 지정된다.
    • 시스템의 현재 타임스탬프 값은 SYS_TIMESTAMP (또는 SYSTIMESTAMP , CURRENT_TIMESTAMP ) 함수를 이용하여 TIMESTAMP 데이터 타입에 저장할 수 있다. 함수 또는 TO_TIMESTAMP() 함수를 사용하면, 문자열 데이터 타입의 데이터를 TIMESTAMP 데이터 타입으로 변환할 수 있다.
    • 연, 월, 일에는 0을 입력할 수 없으나 예외적으로 연, 월, 일, 시, 분, 초가 모두 0인 '0000-00-00 00:00:00'은 입력할 수 있다. GMT timestamp'1970-01-01 12:00:00 AM' 또는 KST timestamp'1970-01-01 09:00:00 AM'은 timestamp'0000-00-00 00:00:00'으로 해석된다.
    • 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.

    DATETIME¶

    DATETIME 타입은 날짜(년, 월, 일)와 시간(시, 분, 초, 밀리초)을 결합한 데이터 값을 표현하며, GMT로 0001-01-01 00:00:00.000부터 9999-12-31 23:59:59.999까지 표현할 수 있다. DATETIME 타입 데이터의 입력 형식은 다음과 같다.

    • 모든 항목은 정수로 입력되어야 한다.
    • 연도를 생략하면 기본값으로 현재 연도가 지정되고, 시간 값(시/분/초/밀리초)를 생략하면 12:00:00.000 AM으로 지정된다.
    • 시스템의 현재 타임스탬프 값은 SYS_DATETIME (또는 SYSDATETIME , CURRENT_DATETIME , CURRENT_DATETIME() , NOW() )를 이용하여 DATETIME 타입에 저장할 수 있다.
    • 문자열 타입의 데이터를 DATETIME 타입으로 변환하는 함수는 TO_DATETIME() 이다.
    • 연, 월, 일에는 0을 입력할 수 없으나 예외적으로 연, 월, 일, 시, 분, 초가 모두 0인 '0000-00-00 00:00:00'은 입력할 수 있다.
    • 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.

    문자열을 날짜/시간 타입으로 CAST¶

    날짜/시간 타입 문자열 권장 형식¶

    CAST() 연산자를 사용하여 문자열을 날짜/시간 타입으로 변환할 때에는 문자열을 다음과 같은 형식으로 작성하는 것을 권장한다. 참고로, CAST() 연산자에서 사용하는 날짜/시간 문자열 형식은 DB 생성 시 지정하는 로캘의 영향을 받지 않는다.

    또한, TO_DATE() , TO_TIME() , TO_DATETIME() , TO_TIMESTAMP() 함수에서 문자열에 대한 날짜/시간 형식을 생략하는 경우에도 날짜/시간 문자열 형식을 아래와 같이 작성한다.

    DATE 타입

    TIME 타입

    DATETIME 타입

    TIMESTAMP 타입

    날짜/시간 타입 문자열 허용 형식¶

    CAST() 연산자는 날짜/시간 문자열에 대해 아래와 같은 형식을 허용한다.

    DATE 문자열 허용 형식

    • 2011-04-20 : 2011년 4월 20일
    • 04-20 : 올해 4월 20일
    • 04/20/2011 : 2011년 4월 20일
    • 04/20 : 올해 4월 20일
    • 20110420 : 2011년 4월 20일
    • 110420 : 2011년 4월 20일
    • 420 : 올해 4월 20일

    TIME 문자열 허용 형식

    • 09:10:15.359 am : 오전 9시 10분 15초(0.359초는 버림)
    • 09:10:15 : 오전 9시 10분 15초
    • 09:10 : 오전 9시 10분
    • :10 : 오전 12시 10분
    • 20110420091015.359 am : 오전 9시 10분 15초
    • 0420091015 : 오전 9시 10분 15초
    • 091015.359 am : 오전 9시 10분 15초
    • 91015 : 오전 9시 10분 15초
    • 1015.359 am : 오전 12시 10분 15초
    • 1015 : 오전 12시 10분 15초
    • 15.359 am : 오전 12시 0분 15초
    • 15 : 오전 12시 0분 15초

    Note

    CUBRID 2008 R3.1 이하 버전에서는 [H]H 형식을 허용했다. 즉 R3.1 이하 버전에서 문자열 '10'은 TIME'10:00:00'으로 변환되었으나, R4.0부터는 TIME'00:00:10' 으로 변환된다.

    영역 바이너리 옵션 타입

    이 문서에서는 다음과 같은 내용을 다룹니다.

    메뉴 설명

    deploy_ref_01_2018.png

    1. 아티팩트 메뉴 영역

    배포를 관리하는 Deploy 구성의 기본 단위입니다. 생성된 아티팩트는 화면 위쪽에 목록 형태로 표시됩니다.

    2. 배포 메뉴 영역

    배포를 진행하는 페이지로 시나리오 생성과 설정을 할 수 있습니다. 시나리오에는 Jenkins-CLI 템플릿, 바이너리 배포, 파일 배포가 있으며, 사용자가 원하는 스크립트를 실행할 수 있도록 직접 명령어를 입력할 수 있습니다.

    • 배포 시나리오 관리
      • 복사
      • 설정
      • 새로 만들기
      • 업로드/다운로드
        • 시나리오 단위의 가져오기/내보내기

        배포 옵션

        서버 그룹
        • 배포할 서버 그룹을 선택할 수 있습니다. 서버 그룹은 서버 그룹 탭에서 생성할 수 있습니다.
        실행 서버
        동시 실행 수

        지정된 서버 그룹 내 서버들에 동시 또는 개별 배포합니다.

        • 0: 동시 실행
        • 1: 한대씩 배포
        • N: 동시 배포 수 지정
        시나리오 실행 실패 시
        • 실행 중단
          • 시나리오 실행 중 오류가 발생하면 시나리오 실행이 중단됩니다.
          • 오류 여부와 관계없이 시나리오가 계속 실행됩니다.

          진행 중인 배포 상태 보기

          배포 중인 시나리오의 진행 상황을 확인할 수 있습니다.

          deploy_ref_02_2018.png

          • 배포 중인 아티팩트를 클릭하면 나타나는 헤더에서 확인하고자 하는 배포 항목을 클릭합니다.
          • 배포 이력 화면에서 'deploying' 상태를 클릭합니다.

          배포 이력

          배포 이력과 배포 설정, 배포 노트의 자세한 내용을 확인할 수 있습니다. * 배포 이력과 이력별 자세한 내용 확인 * 배포 결과 * 결과 보기에서 이력별 시나리오 설정 내용과 태스크별 실행 결과, 배포 노트를 확인할 수 있습니다. * 'deploying' 상태일 때 클릭하면 배포 중인 상태 보기 화면으로 이동합니다.

          배포 이력을 실행일 및 서버 그룹을 기준으로 검색할 수 있습니다. * 배포 이력을 실행일 및 서버 그룹을 기준으로 검색 * 서버 그룹 선택 창 및 실행일 시작일~종료일로 검색할 수 있습니다. * 실행일 기간이 1년을 초과하여 선택할 수 없습니다(예: 2020-06-07~2021-06-17).

          검색된 배포 이력을 Excel 파일로 다운로드할 수 있습니다. * 검색된 배포 이력을 Excel 파일로 다운로드 * 원하는 서버 그룹 및 실행일을 선택한 후 다운로드 버튼을 클릭합니다. * 바이너리 파일 없는 이력 제외 옵션을 선택하여 다운로드할 수 있습니다. * 바이너리 파일 없는 이력 제외 선택 없이 다운로드 클릭 시 * 바이너리 파일 없는 이력 제외 선택 후 다운로드 클릭 시

          바이너리 그룹

          바이너리 그룹 탭에서는 바이너리를 그룹으로 관리할 수 있습니다. Develop, Staging, Product 등의 서버 장비에 배포되는 바이너리를 구분할 때 활용할 수 있습니다.

          deploy_ref_04_2018.png

          • 그룹을 생성, 수정하고, 바이너리 파일을 업로드, 다운로드할 수 있습니다.

          deploy_ref_05_2018.png

          • Client 타입일 때는 바이너리 그룹의 비밀번호를 설정할수 있으며, 공유된 클라이언트 다운로드 페이지의 접근을 제어할 수 있습니다.
            • 바이너리 그룹을 생성할 때 바이너리 그룹 비밀번호 사용을 선택하면 비밀번호를 입력할 수 있습니다.
            • 해당 그룹 다운로드 페이지는 NHN Cloud에 로그인하지 않고도 설정된 비밀번호로만 접근할 수 있습니다.

            deploy_ref_06_2018.png

            서버 그룹

            deploy_ref_07_2018.png

            배포 대상 서버를 그룹으로 관리할 수 있습니다. Phase 속성으로 Develop, Staging, Product 등의 서버 장비를 구분하여 활용할 수 있습니다.

            • 그룹, 서버 정보를 수정할 수 있습니다.
            • 그룹에서 사용할 시나리오를 설정할 수 있습니다.

            서버 그룹 추가

            deploy_ref_08_2018.png

            • Deploy 아래의 탭 중 배포 >서버 그룹 생성을 클릭하거나, 서버 그룹 >새로 만들기를 클릭합니다.
              • 이름(필수), 설명(선택) 항목을 입력합니다.
              • OS를 선택한 후 Shell Type를 지정합니다. 목록에서 항목을 선택하거나 직접 입력할 수 있습니다.
              • Phase를 선택합니다. 서버 장비를 구분합니다. 지정하지 않으려면 NONE을 선택합니다.
              • 생성 버튼을 클릭합니다.

              서버 정보 추가/삭제

              서버 그룹 생성(수정) 창에서 서버 정보를 추가하거나 삭제할 수 있습니다.

              서버 정보 추가

              deploy_ref_08_2018.png

              • 호스트 이름(필수), IP 주소(필수), OS(선택) 입력 후 추가 버튼을 클릭합니다.
              • 아래 서버 목록에 추가된 내용을 확인합니다. 왼쪽 체크 박스에 선택된 서버만 등록됩니다.

              생성 버튼을 클릭합니다. 수정할 때는 수정 버튼을 클릭합니다.

              deploy_ref_09_2018.png

              아래와 같은 형식으로 서버 영역 바이너리 옵션 타입 정보를 입력합니다. test.host.name1;1.1.1.1;CentOS6.8; test.host.name2;2.2.2.2;;

              거래 永川市

              ZeroMQ는 풍부한 오픈 소스 라이선스로 소스 코드 라이선스를 제공합니다. 이 페이지는 iMatix에 의해 빌드, 릴리스 및 지원되는 공식 배포판을 나열합니다. 커뮤니티 위키는 다른 패키지를 제공 할 수 있습니다. 현재 안정 릴리스 4 2 1. 현재 4x stable 릴리스는 v4 2입니다. 1, 2016 년 12 월 32 일부터 변경된 사항 언어 바인딩을 확인하고 이미 ZeroMQ v4 x를 지원하는지 확인합니다. ZeroMQ로 새로운 응용 프로그램을 개발하는 모든 사용자에게이 릴리스를 권장합니다. 모든 4x 릴리스는 안정적인 릴리스와의 호환성을 목표로합니다. 레거시 안정 릴리스 4 1 6. 레거시 4 1x 안정 릴리스는 2016 11 01에서 v4 1 6으로 변경되었습니다. 언어 바인딩을 확인하고 이미 ZeroMQ v4를 지원하는지 확인하십시오. 4로 업그레이드하는 것이 좋습니다. 2 x 모두 4 x 안정적인 릴리스와의 호환성을 목표로합니다. 2 2 0. 레거시 안정 릴리스 4 0 8. 레거시 4 0 x 안정 릴리스는 v4 0 8, 2016 06 17에서 변경되었습니다. 언어 바인딩을 확인하고 이미 지원하는지 확인하십시오 ZeroMQ v4 x 권장 4로 업그레이드 2 x 모든 4x 릴리스는 안정적인 릴리스와의 호환성을 목표로합니다. 2 2. 안정적인 릴리스 3 2 5. 기존 3x stable 릴리스는 v3 2 5, 2014 10 14에서 변경되었습니다. 누구나 3 2 x 또는 2 2 x를 사용하여 4 1x로 업그레이드하십시오. 도움이 필요하면 zeromq-dev maling list에 문의하십시오. 개발 마스터. 우리의 목표는 개발 마스터가 거의 완벽하다는 것입니다. 항상 얻을 수 있습니다. git을 통해 언제든지 최신 개발 마스터를 사용할 수 있습니다. 새 응용 프로그램을 개발하는 경우 정기적으로 마스터에 대해 테스트하는 것이 좋습니다. Linux 및 OS X의 마스터에서 빌드하십시오. VS2015를 사용하여 Windows의 마스터에서 빌드하십시오. 이전 버전. 다른 소프트웨어. CC에서 일하고 있다면 UDP와 가십 발견, 반응기, 컨테이너, 스마트 소켓 및 동시 프로그래밍을위한 액터를 포함하여 ZeroMQ 위에 많은 유용한 클래스를 추가하는 고급 C 바인딩 인 CZMQ를 얻길 원할 것입니다. 유닉스와 유사한 시스템에서 빌드하십시오. 자유로운 선택이 있다면, dev에 가장 편안한 OS ZeroMQ로 도망가는 것은 아마도 Ubuntu 일 것입니다. libtool pkg-config 빌드 필수 필수 autoconf와 automake가 설치되었는지 확인하십시오. uuid-dev 패키지, uuid e2fsprogs RPM 또는 이에 상응하는 시스템이 설치되었는지 확인하십시오. 소스 아카이브를 압축 해제하십시오. ZeroMQ를 설치하려면 시스템 전체에서 sudo make install을 실행하십시오. Linux에서는 ZeroMQ를 설치 한 후 sudo ldconfig를 실행하십시오. 구성 옵션을 보려면 configure --help를 실행하십시오. 자세한 내용은 INSTALL을 읽으십시오. Windows에서 빌드하려면 Visual Studio 2008 또는 나중에. 소스 아카이브 압축을 풉니 다. Visual C에서 솔루션을 엽니 다. 솔루션을 만듭니다. ZeroMQ 라이브러리는 lib 하위 디렉토리에 있습니다. 언어 바인딩. 전체 언어 바인딩 목록을 보려면 여기를 클릭하십시오. 순수 언어 스택. ZeroMQ는 pure Java 스택은 JeroMQ이고 NetMQ는 순수한 C 스택입니다. 이들은 모두 공식 프로젝트이며 ZeroMQ 커뮤니티에서 지원합니다. Tuning ZeroMQ. 이 wiki 페이지에는 ZeroMQ 튜닝에 대한 팁이 들어 있습니다. 그것들을 발견하십시오. 웹 사이트 디자인과 내용은 저작권이 있습니다. c 2014 iMatix Corporation 전문적인 지원을 위해 연락하십시오. cc-by-sa하에 라이센스 된 사이트 컨텐츠 3 0 MQ는 저작권이 있습니다. c Copyright c 2007-2014 iMatix Corporation 및 기여자 MQ는 LGPL MQ 및 ZEROMQ는 iMatix Corporation의 상표입니다. 사용 조건 개인 정보 보호 정책. int zmqsetsockopt void socket int optionname const void optionvalue sizet optionlen. Caution ZMQSUBSCRIBE, ZMQUNSUBSCRIBE, ZMQLINGER, ZMQROUTERMANDATORY 및 ZMQXPUBVERBOSE를 제외한 모든 옵션은 후속 소켓에만 적용됩니다 zmqsetsockopt 함수는 optionname 인수에 지정된 옵션을 socket 인수가 가리키는 MQ 소켓의 optionvalue 인수가 가리키는 값으로 설정합니다. optionlen 인수는 옵션 값의 크기 (바이트)입니다. 다음 소켓 옵션은 zmqsetsockopt 함수로 설정할 수 있습니다. ZMQSNDHWM 아웃 Y 운드 메시지의 최고 수위를 설정하십시오. ZMQ SNDHWM 옵션은 지정된 소켓에서 아웃 바운드 메시지의 최고 수위 표시를 설정해야합니다. 최고 수위 표시는 지정된 소켓이 통신중인 단일 피어에 대해 MQ가 메모리에 대기열에 넣을 최대 메시지 수에 대한 하드 제한입니다. 이 제한 도달 한 소켓은 예외적 인 상태가되고 소켓 유형에 따라 MQ는 보낸 메시지 차단 또는 삭제와 같은 적절한 조치를 취합니다. 각 소켓 유형에 대해 수행 된 정확한 작업에 대한 자세한 내용은 zmqsocket 3의 개별 소켓 설명을 참조하십시오. MQ는 소켓이 ZMQSNDHWM 메시지를 허용한다는 것을 보증하지 않으며 socket. Option 값 type. Etermax Games Stock Trading의 메시지 흐름에 따라 실제 한계가 60-70 정도 더 낮을 수 있습니다. 모바일 장치 소유자가 다운로드하고 설치할 수있는 말 그대로 무료 및 유료 앱 수백만 개가 있습니다. 2015 년의 상위 10 개 무료 앱에는 미디어 스트리밍 서비스, 소셜 네트워킹 플랫폼 및 장치 유틸리티가 포함됩니다. Etermax 영역 바이너리 옵션 타입 Games Stock Trading Oil In Forex Trading In 나이지리아 게임 만화 전자 서적 펌웨어 영역 TradeFields - 주식 시장 시뮬레이터 Etermax 지금 다운로드 지금 다운로드 업데이트 된 게임 TradeFields - 주식 시장 시뮬레이터 대부분의 앱이 성공하지 못하고 제작자의 백만장자를 밤새 만들지는 않지만 일부는 그렇습니다 두 회사가 Supercell과 King KING을 장악하고 있습니다. Apple은 자사의 앱 스토어가 2015 년 매출 100 억 이상을 가져올 것으로 예측하므로 올해까지 지금까지 가장 큰 앱을 살펴볼 가치가 있습니다. 앱 순위에는 인기있는 무료 앱 3 가지 카테고리가 있는데, 다운로드에는 비용이 들지 않지만 인앱 구매 또는 프리미엄 버전을 제공 할 수 있습니다 더 많은 것을 가진 이온 및 더 나은 특징 0 99에서 다운로드하는 수십 달러까지 사용자에게 어느 곳에서든지 요하는 대중적인 급여받는 apps 및 특정 app에 벌린 수익의 모든 근원을 설명하는 최고 수익 발생 apps, Etermax Games 주식 거래 정보 Investigacin 델 메르 카도 데 베네수엘라 거래 절약 중소 기업 시장 경제 싱가포르 기술 속성 블로그 사진 비디오 베스트 iPad 주식 시장 애플 리케이션 주식 전문가는 iPad에 대한 강력한 주식 분석 애플 리케이션이지만 그것은 거래 일 동안 5 분 간격으로 이루어집니다 게임 만화 E - Books Firmware Zone TradeFields - 증권 시장 시뮬레이터 Etermax 지금 다운로드 지금 다운로드 업데이트 된 게임 TradeFields - 주식 시장 시뮬레이터 사용자가 일관되게 지불하는 최고 응용 프로그램은 게임입니다. Forex 마진 요구 사항 Thinkerswim Tutorial. Delta 중립 Fx 옵션 전략. Etermax Games Stock Trading Goldfinger How Do 바이너리 옵션 브로커 머니 거래 만들기 중소 기업 시장 절약 경제 싱가포르 기술 속성 블로그 사진 비디오 이진 옵션 Forex Warrior On Cboe 게임 Mangas 전자 책 펌웨어 영역 TradeFields - 주식 시장 시뮬레이터 Etermax 지금 다운로드하십시오. 최신 게임 TradeFields - Stock Market Simulator. It 또한 주목할 가치가 있습니다. 하이테크 기업의 제품이 아니며 개인 개발자의 제품이 아닙니다. 자세한 내용은 다운로드 할 항목이 들지 않지만 인앱 구매 또는 더 많은 프리미엄 버전을 제공하는 인기 앱의 세 가지 일반 카테고리가 있습니다 또는 더 나은 기능을 제공합니다. 0 99에서 최대 수십 달러까지 다운로드 할 수있는 인기있는 유료 앱 및 특정 앱에서 얻은 모든 수익원을 고려한 최고의 수익 창출 앱 Etermax Games 401k 영역 바이너리 옵션 타입 투자 옵션 조언 흥미로운 것은 최고 유료 및 최고 총 수익을 올리는 앱이 완전히 게임으로 구성된다는 것입니다. Etermax Games Stock Trading Inc NYSETIME이 오늘 Trivia Crack의 속편을 시작하는 모바일 게임 개발자 인 Etermax와 콘텐츠 파트너십을 체결했습니다. 모바일 앱은 Apple i Tunes AAPL 및 Google Play GOOG와 같은 플랫폼을 제공하는 큰 돈을 벌어들입니다. 행운의 개발자가 큰 성공을 거둔 행운아 개발자 Etermax Games 주식 거래 우리를 거래하는 방법 주식 시장 온라인 주식 시장에서 돈을 사용하는 방법 Market. zmqsetsockopt - MQ 소켓 옵션을 설정하십시오. zmqsetsockopt void socket int optionname const void optionvalue sizet optionlen. Caution 모든 옵션 ZMQSUBSCRIBE, ZMQUNSUBSCRIBE, ZMQLINGER, ZMQROUTERHANDOORY, ZMQROUTERMANDATORY, ZMQPROBEROUTER, ZMQXPUBVERBOSE, ZMQREQCORRELATE 및 ZMQREQRELAXED는 이후의 소켓 바인드 연결에만 적용됩니다. 특히 보안 옵션은 후속 바인드 연결 호출에 적용되며 후속 바인드 및 연결에 영향을 줄 수 있습니다. zmqsetsockopt 함수는 optionname argu로 지정된 옵션을 설정해야합니다. ment 인수는 소켓 인수가 가리키는 MQ 소켓의 optionvalue 인수가 가리키는 값으로 변경합니다. optionlen 인수는 옵션 값의 크기 (바이트)입니다. 다음 소켓 옵션은 zmqsetsockopt 함수로 설정할 수 있습니다. ZMQAFFINITY IO 스레드 선호도 설정 ZMQAFFINITY 옵션은 지정된 소켓에서 새로 생성 된 연결에 대한 IO 스레드 선호도를 설정해야합니다. 크기는 소켓의 컨텍스트와 연관된 MQ IO 스레드 풀의 어떤 스레드가 새로 생성 된 연결을 처리할지 결정합니다. 0 값은 친화력을 지정하지 않습니다. 작업은 스레드 풀의 모든 MQ IO 스레드간에 공평하게 분산되어야합니다. 0이 아닌 값의 경우 가장 낮은 비트는 스레드 1에 해당하고 두 번째로 낮은 비트는 스레드 2에 해당합니다. 예를 들어 값 3은 소켓의 후속 연결 는 IO 쓰레드 1과 2만으로 처리됩니다. 특정 컨텍스트에 대한 IO 쓰레드의 수를 할당하는 것에 대한 자세한 내용은 zmqinit 3을 참조하십시오. 옵션 값 유형. Ze roMQ 3 소켓 옵션 Identity 및 SendMore. Last 시간에 우리는 ZeroMQ 내의 다른 소켓 유형을 살펴 보았습니다. 그리고 NetMQ에서 이것들에 대해서도 말씀 드렸습니다. 이것들은 내가이 게시물에 사용하는 것입니다. 이번에는 ZeroMQ의 3 개의 작은 영역을 살펴보고, 그다지 중요하지 않은 영역은 아니며 간과해서는 안됩니다. 이 영역은 소켓 옵션 인 Identity 및 SendMore입니다. 코드는 어디입니까? 이러한 모든 게시물에 대한 코드는 github. Socket Options의 한 가지 큰 솔루션에서 호스팅됩니다. 사용하려는 소켓 유형 또는 생성하려는 토폴로지에 따라 일부 ZeroMQ 옵션을 설정해야하는 경우가 있습니다. NetMQ에서이 작업은 속성을 사용하여 수행됩니다. 여기에 사용할 수있는 속성 목록이 있습니다. xxxxSocket 당신이 달성하려고하는 것에 분명히 의존하기 때문에이 값들 중 어느 값을 설정해야하는지 정확하게 말하기는 어렵습니다. 내가 할 수있는 것은 옵션을 나열하고 그것을 당신에게 알려주는 것입니다. 그래서 여기 있습니다. 이 옵션들이 무엇을 의미하는지 정확히 알아라. 실제 ZeroMQ 문서, 즉 가이드를 참조 할 필요가있을 것입니다. ZeroMQ로 작업 할 때 필자가 생각한 것 중 가장 큰 것 중 하나는 우리가 여전히 표준 요청 응답 배열을 고수 할 수 있다는 것입니다. 안녕하세요 세계 예제지만 우리는 다음 비동기 서버로 전환하도록 선택할 수 있습니다 이것은 쉽게 서버에 대한 RouterSocket을 사용하여 달성 클라이언트가 RequestSocket으로 남아있어. 이제 이것은 흥미로운 배열, 우리가 가지고 있습니다. 표준 RequestSocket 유형입니다. 비동기 서버 인 RouterSocket이라는 새로운 소켓 덕분에. RouterSocket은 개인적으로 좋아합니다. ZeroMQ 소켓의 많은 기능을 사용하면 매우 쉽게 사용할 수 있습니다. RequestSocket을 사용하여 작업 할 때, 그들은 당신을 위해 영리한 일을 할 수 있습니다. y는 항상 다음 프레임을 가진 메시지를 제공합니다. Frame 0 address. Frame 1 empty frame. Frame 2 메시지 payload. Iven은 Hello World 예제를 part1에 보냅니다. 그렇지만 ResponseSocket 우리는 무거운 짐을 싣고 다음과 같은 프레임이있는 메시지를 제공합니다. Frame 0 return address. Frame 1 empty frame. Frame 2 메시지 페이로드입니다. 우리가 한 것은 페이로드를 보내지 만 표준적인 동기식 요청 응답 소켓이 어떻게 작동하는지 이해함으로써 올바른 클라이언트에 메시지를 다시 보내는 방법을 알고있는 RouterSocket을 사용하여 완전히 비동기적인 서버를 만드는 것이 매우 쉽습니다. 우리가해야 할 모든 것 표준 ResponseSocket이 작동하는 방식을 에뮬레이션합니다. 여기서는 메시지 프레임을 직접 구성합니다. RouterSocket에서 다음 프레임을 생성하여 표준 ResponseSocket. Fram의 동작을 에뮬레이트 할 것입니다. e 0 return address. Frame 1 empty frame. Frame 2 메시지 페이로드입니다. 이걸 이해하는 가장 좋은 방법은 예제를 통해 생각합니다. 이 예제는 다음과 같이 작동합니다 .4 개의 클라이언트가 있으며, 이들은 표준 동기식 RequestSocket입니다. 단일 비동기 서버는 RouterSocket을 사용합니다. 클라이언트가 접두어 B를 사용하여 메시지를 보내면 서버에서 특수 메시지를받습니다. 다른 모든 클라이언트는 표준 응답 메시지를받습니다. 더 이상 생각해 보면이 예제의 전체 코드는 다음과 같습니다. System. namespace를 사용하여 NetMQ를 사용하여 사용하여 사용하기 ZeroMqIdentity public class Program IDisposable private ListSequence 클라이언트 new 목록 RequestSocket. public void var 서버 tcp를 사용하는 NetMQContext ctx NetMQContext 127 0 0 1 5556.CreateClient ctx, A CreateClient ctx, B CreateClient ctx , C CreateClient ctx, D. var clientMessage 콘솔 콘솔 들어오는 클라이언트 메시지 int i 0 ii 콘솔 콘솔 프레임 i. var clientAddress clientMessage 0 var clientOriginalMessage string re 서버 clientOriginalMessage의 sponse 문자열을 반환합니다. B 클라이언트가 특수한 경우 B 응답 문자열 special server. var에서 B에 대한 메시지 messageToClient new NetMQMessage. private static void 주 문자열 args 프로그램 p 새 Program. private void CreateClient NetMQContext ctx, string 접두어 작업 var client tcp 127 0 0 1 5556 string 안녕 접두사. 클라이언트 메시지를 읽습니다. var echoedServerMessage Console r nClient Prefix는 서버 메시지 접두사 인 echoedServerMessage입니다. 이 예제를 고맙게 생각한다고 가정 해 봅시다. 출력 결과를 조사해야하는데, 정확히 같지 않아야합니다. RouterSocket이 FULLY이므로 비동기이므로 RequestSocket을 다른 순서로 처리 할 수 ​​있습니다. 클라이언트 접두사는 A, 서버 메시지 AHello는 서버에서 시작합니다. 클라이언트 메시지는 프레임 0 프레임 1 프레임 2 BHello. Client 접두사는 D, 서버 메시지 DHello back from server INCOMING 클라이언트 메시지 프레임 0 B 프레임 1 프레임 2 CHello. Client 접두사는 B, 서버 메시지 특수입니다. ser ver. Client 접두사는 C, 서버 메시지에서 B로 되돌아갑니다. 서버에서 되돌아옵니다. ZeroMQ는 메시지 프레임을 사용하여 작동합니다. ZeroMQ를 사용하면 와 같은 여러 가지 이유로 사용할 수있는 여러 부분으로 된 메시지를 만들 수 있습니다. 위에서 설명한 예를 실제로 보았던 주소 정보를 포함합니다. 목적을 위해 프로토콜을 디자인합니다. 직렬 전송 예를 들어 첫 번째 메시지 프레임은 항목의 유형이 될 수 있고 다음 메시지 프레임은 실제 직렬화 된 데이터가 될 수 있습니다. 다중 메시지로 작업 할 때는 작업하려는 메시지의 모든 부분을 보내야합니다. 가장 좋은 방법은 여러 부분으로 된 메시지를 이해하는 것입니다. 아마도 작은 테스트를 통해 제가 원래의 Hello World 요청 응답 데모를 기반으로하는 하나의 데모에서 모두 사용하도록 고집했습니다. NUnit을 사용하여 사이에 데이터에 대한 Asserts를 수행합니다. 클라이언트 서버. 여기에 다음 사항을주의해야 할 작은 테스트 케이스입니다. 우리는 첫 번째 메시지 부분을 구성하고 첫 번째 메시지를 보내는 방법을 사용합니다. 우리는 두 번째 및 마지막 메시지 부분을 메서드를 사용하여 구성합니다. 서버 첫 번째 메시지 부분을 수신 할 수 있고 또한 더 많은 부분이 있는지 결정하기위한 값을 할당 할 수 있습니다. 이 부분의 오버로드를 사용하여 더 많은 값을 얻을 수 있습니다. 실제 NetMqMessage를 사용하여 추가 할 수도 있습니다 그 다음에 우리가 볼 수있는 사용중인 소켓을 사용하여 실제 NetMqMessage 프레임을 검사 할 수 있습니다. 여기에 사용 된 NetMQ using. namespace를 사용하는 시스템입니다. SendMore TestFixture public class SendMoreTests Test public void SendMoreTest using NetMQContext ctx var server tcp를 사용하는 NetMQContext 127 0 0 1 5556.using var client tcp 127 0 0 1 5556. client send message 안녕하세요. 서버 수신 1 부 bool 더 많은 문자열 m out Assert A assert. 서버는 두 번째 부분 문자열 m2를받습니다. Hello m2 Assert를 어설 션하십시오. 서버가 메시지를 보내면이 시간에 클라이언트가 ReceieveMessage var m3 새 NetMQMessage From Server를 호출하면 프레임으로 전송되는 NetMqMessage를 사용합니다. 클라이언트가 var m4 Assert Assert를 Assert Server에서 수신합니다. 여기서는 SendMore 및 여러 부분 메시지로 작업 할 때 Zero Guide에서 실제로 중요한 몇 가지 사항을 제시합니다. 이 내용은 NetMQ 버전이 아니라 ZeroMQ C 구현에 대한 것입니다. NetMQ를 사용할 때 유효합니다. 멀티 파트 메시지에 대해 알아야 할 사항이 있습니다. 멀티 파트 메시지를 보내면 마지막 파트를 보낼 때 첫 번째 파트와 모든 후속 파트가 실제로 전 송됩니다. 받을 때 zmqpoll을 사용하는 경우 메시지의 첫 부분, 나머지는 모두 도착했습니다. 메시지의 모든 부분을 수신하거나 전혀 수신하지 않습니다. 메시지의 각 부분은 별도의 zmqmsg 항목입니다. 메시지의 모든 부분은 메시지의 모든 부분을 수신합니다 당신은 더 많은 프로퍼티를 체크한다. MQ는 메시지를 전송할 때까지 메모리에 메시지 프레임을 큐에 넣은 다음 모든 메시지를 보낸다. 소켓을 닫는 것 외에는 부분적으로 보낸 메시지를 취소 할 방법이 없다. 게시물에 대해, 그래서까지 다음 번에.


0 개 댓글

답장을 남겨주세요