• JAVA의 객체가 garbage collection 대상이 되는 순간은?
    1. reference가 영원히 영역을 벗어남 (ex. 지역 변수로 선언한 객체의 메소드의 영역을 벗어남)
    2. reference에 다른 객체를 대입
    3. reference를 직접 'null'로 설정
    but, 위 방법 외에 참조를 약하게 만들어 GC 대상이 되도록 만들 수 있다.

Strong Reference > Soft Reference > Weak Reference > Phantom Reference

  • Strong Reference
    : 일반적으로 new를 통해서 객체를 생성하게 되면 생기게 되는 참조.
    : 참조에 대해서 해지하지 않는다면 그 메모리는 절대 수거되지 않는다.

  • Soft Reference
    : GC에 의해 수거될 수도 있고, 수거되지 않을 수도 있다.
    : 메모리 상태에 따라 결정

  • Weak Reference
    : GC가 발생하기 전까지는 참조를 유지한다.
    : GC가 발생하는 순간 무조건 수거된다.
    : 객체 캐시에 유용 (안드로이드에서 그림이 포함된 listView 등)

  • Phantom Reference
    : 가장 약한 참조
    : GC가 발생 전 메모리에서 정리된다. (finalize() 호출 후)
    : 내부적으로 유지하고 있지만, 객체를 다시 꺼내오면 null 이다 

    - ReferenceTest.java
    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import java.lang.ref.SoftReference;
    import java.lang.ref.WeakReference;
    import java.util.LinkedList;
    import java.util.List;
    
    // 강한 참조(Strong Reference)
    // 일반적으로 new를 통해서 객체를 생성하게 되면 생기게 되는 참조.
    
    // 강한 참조를 통해 참조되고 있는 객체는 절대 가비지 컬렉션의 대상에서
    // 제외된다.
    // 자바에서 아무리 자동적으로 메모리가 수거된다고 하지만, 
    // 참조에 대해서 해지하지 않는 다면 그 메모리는 절대 수거되지 않는다.
    //  (참조 = null , 참조 = 다른객체)
    
    // OutOfMemory를 방지하기 위해서는 약한 형태의 참조를 사용해야 한다.
    //  SoftReference<>, WeakReference<>
    
    // Soft Reference
    // 생성 방법 : SoftReference<Data> r
                // = new SoftReference<Data>(new Data);
    // 동작 : 강한 참조와 다르게 GC에 의해 수거될 수도 있고, 수거되지 않을 수도 있다.
    //  메모리에 충분한 여유가 있다면 GC가 수행되고 있다고 하더라도 수거되지 않는다.
    //  하지만 out of memory의 시점이 가깝다면, 수거될 확률이 높다.
    
    // Weak Reference
    //생성 방법 : WeakReference<Data> r
    // = new WeakReference<Data>(new Data);
    
    // WeakReference에 의해 참조된 객체는 가비지 컬렉션이 발생하기 전까지는 참조를 유지
    // 하지만 GC가 발생하는 순간 무조건 수거된다.
    // WeakReference가 사라지는 시점이 GC의 실행 주기와 일치한다.
    // 이를 이용하면 짧은 주기에 자주 사용되는 객체를 캐시할 때 유용하다.
    // => WeakHashMap
    // WeakHashMap<K,V>
    
    // PhantomReference
    
    class BigData {
    	private int[] array = new int[5000]; // 20000byte, 20K
    }
    
    public class ReferenceTest {
    
    	private List<WeakReference<BigData>> refs = new LinkedList<>();
    
    	public void referenceTest() {
    		try {
    			for (int i = 0; true; i++) {
    				refs.add(new WeakReference<BigData>(new BigData()));
    			}
    		} catch (OutOfMemoryError ofm) { // Strong일 경우 out of memory 발생
    			System.out.println("out of memory!");
    		}
    	}
    
    	public static void main(String[] args) {
    		System.out.println("run");
    		// Thread.sleep(10 * 1000);
    		ReferenceTest test = new ReferenceTest();
    		test.referenceTest();
    		System.out.println("finish");
    	}
    	
    }
    

    - WeakSingleton.java
    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    import java.lang.ref.WeakReference;
    
    public class WeakSingleton {
    	private static WeakReference<WeakSingleton> instance
    	 = new WeakReference<WeakSingleton>(null);
    
    	public static WeakSingleton getInstance()
    	{
    		WeakSingleton m = instance.get();
    		if (m != null)
    			return m;
    		
    		synchronized (WeakSingleton.class) {	
    			
    			System.out.println("Create new instance");
    			
    			m = new WeakSingleton();
    			instance = new WeakReference<WeakSingleton>(m);		
    		}
    		
    		return m;
    	}
    	
    	public static void main(String[] args) {
    		WeakSingleton w = WeakSingleton.getInstance();
    		
    		// System.gc();
    		
    		w = WeakSingleton.getInstance();
    	}
    }
    


'Programing > Java' 카테고리의 다른 글

Effective Java - 객체 생성  (0) 2016.03.03
Java Reference와 GC  (0) 2016.02.29
Garbage Collection  (0) 2015.11.15
Wrapper클래스,박싱(boxing),언박싱(unboxing)  (0) 2015.11.15
Collection  (0) 2015.11.15
  • Protocol Buffers

    : 하나의 언어만으로 서버를 구성하는 것은 한계가 있다. 특히, java와 C#등으로 패킷을 만드는 것은 굉장히 불편하다.
    : 이런 언어적인 차이를 해결해주는 구글의 오픈소스 Protocol Buffers가 있다. 
    : 프로토콜 자체를 언어 독립적으로 구현할 수 있다.

    : node.js에는 npm
    https://developers.google.com/protocol-buffers/


  • Snappy
    : 패킷을 만드는 것 만큼 패킷의 양을 줄이는 것도 중요하다. 특히 모바일에서는 패킷의 양을 줄이는데 신경써야한다.
    : 패킷을 줄이려면 압축과 압축해제를 해야하는데 이 과정에서 속도도 중요하다.
    : 구글 오픈소스 Snappy
    - https://google.github.io/snappy/


  • IOCP
    Input/Ouptput Completion Port
    : Proactor 방식의 고성능 I/O Notification Model로 asynchronous I/O 지원
    : Windows OS가 직접 효율적인 스레드 풀링 제공으로 context switching을 줄임
    : Overlapped I/O를 확장 시킨 개념으로 커널영역과 유저영역의 버퍼 공유 (memory page-locking)

     

    - 기본 동작 구조 (출처: http://www.slideshare.net/sm9kr/windows-registered-io-rio)
     : I/O initiation -> I/O processing -> I/O completion





    - 1_IOCP
     : worker thread 도입

     
    #pragma comment(linker, "/subsystem:console")
    
    #define WIN32_LEAN_AND_MEAN  
    #include <stdio.h>
    #include <WinSock2.h> 
    #include <Windows.h>  
    #pragma comment(lib, "ws2_32.lib") 
    
    #pragma comment(linker, "/subsystem:console")
    
    // Overlapped 작업의 종료를 대기할 스레드
    DWORD __stdcall EchoThread( void* p )
    {
    	// 여기서 비동기작업의 종료를 대기하면 됩니다.
    	// 즉 WSAWait....()
    }
    
    int main()
    {
    	WSADATA w;
    	int ret = WSAStartup( MAKEWORD(2,2), &w);    
    	
    	//-------------------------------------------
    	// 1. Overlapped io를 위한 소켓 생성
    	// 표준 C 네트워크 함수 : 소문자()
    	// WSAxxxx() 함수들 : windows socket 2.0 부터 지원되는
    	//					windows만의 개념들..
    	int listen_sock = WSASocket( PF_INET, SOCK_STREAM,
    								0, 0, 0,
    								WSA_FLAG_OVERLAPPED);
    								
    
    
    
    	// 2. 소켓에 주소 지정(bind)
    	SOCKADDR_IN addr; 
    
    	addr.sin_family = AF_INET;
    	addr.sin_port   = htons(4000);
    	addr.sin_addr.s_addr = INADDR_ANY; 
    	
    	bind( listen_sock, (struct sockaddr*)&addr, sizeof addr);
    
    
    	listen(listen_sock,  5); 
    
    	while(1)
    	{
    		struct sockaddr_in addr2;
    		int sz = sizeof addr2;
    
    
    		int link_sock = accept( listen_sock, 
    							  (struct sockaddr*)&addr2, &sz);
    
    		printf("클라이언트가 접속되었습니다\n");
    
    		// Overlapped로 수신 하는 코드
    		WSAEVENT ev = WSACreateEvent();
    		WSAOVERLAPPED ov = {0};
    		ov.hEvent = ev;
    
    		// 수신 버퍼..
    		char s[1024] = {0};
    		WSABUF buf;
    		buf.buf = s;
    		buf.len = 1024;
    		DWORD flag = 0;
    		DWORD recvBytes = 0;
    
    		int n = WSARecv( link_sock,
    						 &buf, 1,  // 버퍼와 버퍼 갯수
    						 &recvBytes, // 받을 data 크기
    						 &flag,
    						 &ov, // overlapped 구조체
    						 0);
    		// 새로운 스레드를 생성해서 비동기 작업의 완료를 대기한다.
    		CreateThread( 0, 0, EchoThread, (void*)ev, 0, 0);
    	}
    
    
    	closesocket( link_sock);
    	//------------------------------
    	WSACleanup(); 
    }
    

    - 2_IOCP
     : worker thread 구현
     : IOCP 생성
     
    #pragma comment(linker, "/subsystem:console")
    
    #define WIN32_LEAN_AND_MEAN  
    #include <stdio.h>
    #include <WinSock2.h> 
    #include <Windows.h>  
    #pragma comment(lib, "ws2_32.lib")
    
    DWORD __stdcall EchoThread( void* p )
    {
    	HANDLE hPort = (HANDLE)p;
    	WSAOVERLAPPED* pov; 
    	DWORD bytes, key;
    
    	while( 1 )
    	{
    		// IOCP에 있는 완료큐에 작업이 들어올때를 대기한다.
    		GetQueuedCompletionStatus( hPort, &bytes, &key,
    				&pov, INFINITE);
    
    		printf("비동기 작업 완료 : %d bytes,  key : %d\n",
    					bytes, key);
    	}
    	return 0;
    }
    
    int main()
    {
    	WSADATA w;
    	int ret = WSAStartup( MAKEWORD(2,2), &w);    
    	
    
    	//--------------------
    	// 1. 입출력 완료 포트(IOCP)를 생성합니다.
    	HANDLE hPort = CreateIoCompletionPort( 
    						(HANDLE)-1, // IOCP에등록할 파일(소켓)
    						0, // 이미 존재 하는 IOCP핸들
    						0, // 완료키
    						2);// IOCP에서 비동기작업을 대기할 스레드
    						// 갯수 (CPU의 갯수만큼이 가장좋다.)
    
    	// 2. 비동기 작업이 완료 될때를 처리할 스레드 생성
    	HANDLE h1 = CreateThread( 0, 0, EchoThread, (void*)hPort,
    							0, 0);
    	HANDLE h2 = CreateThread( 0, 0, EchoThread, (void*)hPort, 0, 0);
    
    
    	//-------------------------------------------
    	int listen_sock = WSASocket( PF_INET, SOCK_STREAM,
    								0, 0, 0,
    								WSA_FLAG_OVERLAPPED);
    	SOCKADDR_IN addr; 
    	addr.sin_family = AF_INET;
    	addr.sin_port   = htons(4000);
    	addr.sin_addr.s_addr = INADDR_ANY; 
    	
    	bind( listen_sock, (struct sockaddr*)&addr, sizeof addr);
    	listen(listen_sock,  5); 
    
    	int cnt = 0;
    	while(1)
    	{
    		struct sockaddr_in addr2;
    		int sz = sizeof addr2;
    		int link_sock = accept( listen_sock, 
    							  (struct sockaddr*)&addr2, &sz);
    
    		// Client와 연결된 소켓의 핸들을 IOCP에 등록한다.
    		// IOCP를 만들때와 IOCP에 장치(파일)을 등록할때 모두 
    		// 아래 함수를 사용합니다.
    		CreateIoCompletionPort( (HANDLE)link_sock,
    								hPort, 
    								cnt++,
    								2);
    
    
    
    		printf("클라이언트가 접속되었습니다\n");
    
    		// Overlapped로 수신 하는 코드
    		WSAEVENT ev = WSACreateEvent();
    		WSAOVERLAPPED ov = {0};
    		ov.hEvent = ev;
    
    		// 수신 버퍼..
    		char s[1024] = {0};
    		WSABUF buf;
    		buf.buf = s;
    		buf.len = 1024;
    		DWORD flag = 0;
    		DWORD recvBytes = 0;
    
    		int n = WSARecv( link_sock,
    						 &buf, 1,  // 버퍼와 버퍼 갯수
    						 &recvBytes, // 받을 data 크기
    						 &flag,
    						 &ov, // overlapped 구조체
    						 0);
    	}
    	//------------------------------
    	WSACleanup(); 
    }
    

    - 3_IOCP
     : overlapped 구조체 확장 -> 입출력당 1개의 자료 구조
     
    #pragma comment(linker, "/subsystem:console")
    
    #define WIN32_LEAN_AND_MEAN  
    #include <stdio.h>
    #include <WinSock2.h> 
    #include <Windows.h>  
    #include <stdlib.h>  
    #pragma comment(lib, "ws2_32.lib")
    
    #define READ_MODE  1
    #define WRITE_MODE 2
    
    // OVERLAPPED 구조체는 보통 확장해서 사용하게 됩니다.
    // 입출력당 1개의 자료 구조
    struct IO_DATA
    {
    	WSAOVERLAPPED ov;
    	WSABUF        wsaBuf;
    	char          buff[1024];
    	int           mode;
    };
    
    DWORD __stdcall EchoThread( void* p )
    {
    	HANDLE hPort = (HANDLE)p;
    	WSAOVERLAPPED* pov; 
    	DWORD bytes, key;
    
    	while( 1 )
    	{
    		// IOCP에 있는 완료큐에 작업이 들어올때를 대기한다.
    		GetQueuedCompletionStatus( hPort, &bytes, &key,
    				&pov, INFINITE);
    
    		printf("비동기 작업 완료 : %d bytes,  key : %d\n",
    					bytes, key);
    
    		IO_DATA* ioData = (IO_DATA*)pov;
    
    		printf("수신된 data : %s\n", ioData->buff);
    
    		CloseHandle( ioData->ov.hEvent);
    		free(ioData);
    	}
    	return 0;
    }
    
    int main()
    {
    	WSADATA w;
    	int ret = WSAStartup( MAKEWORD(2,2), &w);    
    	
    
    	//--------------------
    	// 1. 입출력 완료 포트(IOCP)를 생성합니다.
    	HANDLE hPort = CreateIoCompletionPort( 
    						(HANDLE)-1, // IOCP에등록할 파일(소켓)
    						0, // 이미 존재 하는 IOCP핸들
    						0, // 완료키
    						2);// IOCP에서 비동기작업을 대기할 스레드
    						// 갯수 (CPU의 갯수만큼이 가장좋다.)
    
    	// 2. 비동기 작업이 완료 될때를 처리할 스레드 생성
    	HANDLE h1 = CreateThread( 0, 0, EchoThread, (void*)hPort,
    							0, 0);
    	HANDLE h2 = CreateThread( 0, 0, EchoThread, (void*)hPort, 0, 0);
    
    
    	//-------------------------------------------
    	int listen_sock = WSASocket( PF_INET, SOCK_STREAM,
    								0, 0, 0,
    								WSA_FLAG_OVERLAPPED);
    	SOCKADDR_IN addr; 
    	addr.sin_family = AF_INET;
    	addr.sin_port   = htons(4000);
    	addr.sin_addr.s_addr = INADDR_ANY; 
    	
    	bind( listen_sock, (struct sockaddr*)&addr, sizeof addr);
    	listen(listen_sock,  5); 
    
    	int cnt = 0;
    	while(1)
    	{
    		struct sockaddr_in addr2;
    		int sz = sizeof addr2;
    		int link_sock = accept( listen_sock, 
    							  (struct sockaddr*)&addr2, &sz);
    
    		// Client와 연결된 소켓의 핸들을 IOCP에 등록한다.
    		// IOCP를 만들때와 IOCP에 장치(파일)을 등록할때 모두 
    		// 아래 함수를 사용합니다.
    		CreateIoCompletionPort( (HANDLE)link_sock,
    								hPort, 
    								cnt++,
    								2);
    
    
    
    		printf("클라이언트가 접속되었습니다\n");
    
    		// IO작업당 아래 구조체를 만들어서 사용한다.
    		IO_DATA* ioData = (IO_DATA*)malloc(sizeof(IO_DATA));
    
    		memset(ioData, 0, sizeof(IO_DATA));
    
    
    		ioData->wsaBuf.buf = ioData->buff;
    		ioData->wsaBuf.len = 1024;
    		ioData->mode = READ_MODE;
    		ioData->ov.hEvent = WSACreateEvent();
    
    
    		DWORD flag = 0;
    		DWORD recvBytes = 0;
    
    		int n = WSARecv( link_sock,
    						 &(ioData->wsaBuf), 1,  // 버퍼와 버퍼 갯수
    						 &recvBytes, // 받을 data 크기
    						 &flag,
    						 (WSAOVERLAPPED*)ioData, // overlapped 구조체
    						 0);
    	}
    	//------------------------------
    	WSACleanup(); 
    }
    

    - 4_IOCP
     : 소켓 구조체 구현 
     : write 구현 -> WSASend 도 완료되면 GetQueuedCompletionStatus로 통보된다.
     
    #pragma comment(linker, "/subsystem:console")
    
    #define WIN32_LEAN_AND_MEAN  
    #include <stdio.h>
    #include <WinSock2.h> 
    #include <Windows.h>
    #include <stdlib.h>  
    #pragma comment(lib, "ws2_32.lib") 
    
    #define READ_MODE  1
    #define WRITE_MODE 2
    
    // 클라이언트와 연결된 소켓정보를 관리하는 구조체
    struct SOCKET_DATA
    {
    	int sock;
    	SOCKADDR_IN addr;
    };
    
    // OVERLAPPED 구조체는 보통 확장해서 사용하게 됩니다.
    // 입출력당 1개의 자료 구조
    struct IO_DATA
    {
    	WSAOVERLAPPED ov;
    	WSABUF        wsaBuf;
    	char          buff[1024];
    	int           mode;
    };
    
    DWORD __stdcall EchoThread( void* p )
    {
    	HANDLE hPort = (HANDLE)p;
    	WSAOVERLAPPED* pov; 
    	DWORD bytes, key;
    
    	while( 1 )
    	{
    		GetQueuedCompletionStatus( hPort, &bytes, &key,
    				&pov, INFINITE);
    
    		printf("비동기 작업 완료 : %d bytes,  key : %d\n",
    					bytes, key);
    
    		SOCKET_DATA* pSock = (SOCKET_DATA*)key;
    
    		IO_DATA* ioData = (IO_DATA*)pov;
    
    		if ( ioData->mode == READ_MODE )
    		{
    			printf("수신된 data : %s\n", ioData->buff);
    
    			// 수신에 사용한 버퍼를 사용해서 송신한다.
    			// 수신중에 overlapped 구조체의 내용은 변경되어 있게됩니다
    			memset( &(ioData->ov), 0, sizeof(WSAOVERLAPPED));
    
    			strcat( ioData->buff, " from server");
    			ioData->mode = WRITE_MODE;
    			//-----------------------------------
    			WSASend( pSock->sock, 
    				 &(ioData->wsaBuf), 1,
    				 &bytes, 0, &(ioData->ov), 0);
    			//-----------------------------
    		}
    		else
    		{
    			closesocket(pSock->sock);
    			free( pSock	);
    			CloseHandle( ioData->ov.hEvent);
    			free(ioData);
    		}
    	}
    	return 0;
    }
    
    int main()
    {
    	WSADATA w;
    	int ret = WSAStartup( MAKEWORD(2,2), &w);    
    	
    
    	//--------------------
    	// 1. 입출력 완료 포트(IOCP)를 생성합니다.
    	HANDLE hPort = CreateIoCompletionPort( 
    						(HANDLE)-1, // IOCP에등록할 파일(소켓)
    						0, // 이미 존재 하는 IOCP핸들
    						0, // 완료키
    						2);// IOCP에서 비동기작업을 대기할 스레드
    						// 갯수 (CPU의 갯수만큼이 가장좋다.)
    
    	// 2. 비동기 작업이 완료 될때를 처리할 스레드 생성
    	HANDLE h1 = CreateThread( 0, 0, EchoThread, (void*)hPort,
    							0, 0);
    	HANDLE h2 = CreateThread( 0, 0, EchoThread, (void*)hPort, 0, 0);
    
    
    	//-------------------------------------------
    	int listen_sock = WSASocket( PF_INET, SOCK_STREAM,
    								0, 0, 0,
    								WSA_FLAG_OVERLAPPED);
    	SOCKADDR_IN addr; 
    	addr.sin_family = AF_INET;
    	addr.sin_port   = htons(4000);
    	addr.sin_addr.s_addr = INADDR_ANY; 
    	
    	bind( listen_sock, (struct sockaddr*)&addr, sizeof addr);
    	listen(listen_sock,  5); 
    
    	int cnt = 0;
    	while(1)
    	{
    		struct sockaddr_in addr2;
    		int sz = sizeof addr2;
    
    		int link_sock = accept( listen_sock, 
    							  (struct sockaddr*)&addr2, &sz);
    
    
    		// 소켓당 하나의 구조체
    		SOCKET_DATA* pSock = (SOCKET_DATA*)malloc(
    									sizeof(SOCKET_DATA));
    		pSock->sock = link_sock;
    		pSock->addr = addr2;
    
    
    		// Client와 연결된 소켓의 핸들을 IOCP에 등록한다.
    		// IOCP를 만들때와 IOCP에 장치(파일)을 등록할때 모두 
    		// 아래 함수를 사용합니다.
    		CreateIoCompletionPort( (HANDLE)link_sock,
    								hPort, 
    								(ULONG_PTR)pSock,
    								2);
    
    
    
    		printf("클라이언트가 접속되었습니다\n");
    
    		// IO작업당 아래 구조체를 만들어서 사용한다.
    		IO_DATA* ioData = (IO_DATA*)malloc(sizeof(IO_DATA));
    
    		memset(ioData, 0, sizeof(IO_DATA));
    
    
    		ioData->wsaBuf.buf = ioData->buff;
    		ioData->wsaBuf.len = 1024;
    		ioData->mode = READ_MODE;
    		ioData->ov.hEvent = WSACreateEvent();
    
    
    		DWORD flag = 0;
    		DWORD recvBytes = 0;
    
    		int n = WSARecv( link_sock,
    						 &(ioData->wsaBuf), 1,  // 버퍼와 버퍼 갯수
    						 &recvBytes, // 받을 data 크기
    						 &flag,
    						 (WSAOVERLAPPED*)ioData, // overlapped 구조체
    						 0);
    	}
    	//------------------------------
    	WSACleanup(); 
    }


    - PAGE_LOCKING
    (참고: 
    http://www.slideshare.net/sm9kr/windows-registered-io-rio,
    http://ozt88.tistory.com/26)
     
     : 완벽한 통지모델로 보이는 IOCP에도 문제는 있다.
     : 하나의 I/O operation마다 버퍼 영역에 대한 page-lock/unlock
      -> 특정 메모리에 대한 pin/unpin은 많은 CPU cycle 요구
      -> 그래서 RECV를 posting 할 때, page-locking을 피하여 CPU cycle을 줄이기 위해 zero-byte recv로 최소화
     : 하나의 I/O operation마다 시스템콜 호출
      -> 유저모드-커널모드 전환 발생


     ■ Zero Byte Recv?
      : 실제 수행을 시작하는 때를 감지할 수 있다면 이 문제를 해결할 수 있다.
      : 비동기 작업을 명령하기 전에 먼저 0바이트를 읽는 Recv작업을 요청하는 것이다. 0바이트 읽는 작업이므로 필요한 버퍼도 0바이트, 그러므로 PAGE_LOCKING이 발생하지 않는다. 비동기 명령 프로세서를 사용하기 때문에 이 명령이 요청된 시점에는 작업이 바로 가능한지 불확실하지만, 이 명령이 완료된 시점에는 다음 작업을 바로 시작할 수 있을 가능성이 매우 높다. 그러니까 이때부터 본격적인(큰 용량의 버퍼를 사용하는) 작업을 요청하는 것이다. 이렇게 하면 최대한 쓸데없이 LOCKING된 메모리를 줄일 수 있다.

     ■ SO_RCVBUF 옵션
      이 옵션은 소켓 버퍼의 크기를 설정하는 옵션이다. 이 옵션을 사용하여 버퍼 크기를 0으로 설정하는 경우, 커널이 따로 소켓버퍼(send, recv 버퍼)를 사용하지않고 직접 유저가 설정한 버퍼(메모리)에 직접 I/O를 때려박는다. 필자는 Memory-mapped file같은 느낌이라고 이해하고 있다. 0으로 설정하면 커널 버퍼를 거치지 않고 직접 유저의 버퍼에 데이터가 저장되기 때문에, 불필요해 보이는 복사가 수행되지 않아서 성능상에 이점이 있다. 위에서 살짝 언급한것처럼 가상메모리의 영역이 하드웨어 메모리 영역과 깊은 커플링을 맺게되면서, PAGE_LOCKING의 원인이 된다. 그렇다면 유저는 복사를 하지 않는 성능 이점과 PAGE_LOCKING의 이슈를 저울질 하여 옵션을 선택해야 할 것이다.



+ Recent posts