반응형


 안녕하세요. 오늘은 프로세스와 스레드에 대해서 알아보도록 하겠습니다. 많은 분들이 실제로 프로세스와 스레드를 알고 계시면서도 막상 물어보면 대답하기 막막해하시는 경우도 많이 있고 저도 실제로 프로세스&스레드에 대해서 명확히 설명하기 힘들어 했던 경험이 있어 이번 기회에 한 번 간단히 개념적인 부분에 대해서 정리하고 넘어가려고 합니다. 이제 막 2년차에 접어드는 현업 개발자지만 요즘 느끼는 것은 새로운 기술들에 관심을 가지는 것도 중요하지만 개발을 함에 필요한 '기본적인 내용들과 지식을 좀 더 단단히 쌓아야 겠다'는 생각이 많이 들곤 합니다. 포스팅 시작하도록 하겠습니다.



[ PROCESS ]

 먼저 프로세스란 간단히 설명해서 실행중인 프로그램에 대한 인스턴스를 프로세스라고 합니다. 실제로 프로세스가 생성되게 되면 해당 프로세스는 운영체제로부터 주소공간, 파일, 메모리 등을 할당받게 됩니다. 그리고 메모리 공간은 CODE, DATA, HEAP, STACK영역으로 나뉘어지게 됩니다. 실제로 프로세스가 처리해야 될 일을 각각의 메모리 영역들 위에서 처리하게 되게 됩니다.

프로세스는 다음과 같은 독립된 메모리공간을 프로세스별로 가지게됩니다. (스레드 설명할 때 설명하겠지만 스레드는 STACK 부분만 독립적으로 가지게 됩니다.) 그렇기 때문에 특정 PROCESS가 다른 PROCESS 메모리에 직접 접근하기 힘듭니다.


[ THREAD ]

 스레드란 프로세스 안에서 동작되는 여러 실행의 흐름이라고 보시면 됩니다. 간단히 말해서 프로세스 내부에서 실제로 일을 하는 녀석들을 스레드라고 합니다. 우리 몸으로 치면 몸은 프로세스 손,발은 스레드 정도가 되지 않을까요?(단순한 제 생각) 기본적으로 하나의 프로세스가 생성되면 하나의 스레드가 같이 생성이됩니다. 이를 메인 스레드라고 부르며, 스레드를 추가로 생성하지 않는 한 모든 프로그램 코드는 메인 스레드에서 실행이 된다고 생각하시면 됩니다. 또한 프로세스는 메인 스레드 외에도 여러개의 스레드를 가질 수 있는데요. 이를 멀티스레드라고 합니다.

 스레드의 경우에도 프로세스와 같이 메모리 공간을 할당 받게 되는데요. 프로세스가 각각의 독립적인 메모리 공간을 할당받는 반면에 스레드의 경우는 Stack영역만을 독립적으로 할당 받게 됩니다. 실제로 Code, Data, Heap영역은 프로세스의 공간을 공유받아 사용하게 됩니다. 이렇듯 프로세스 내에서 생겨나는 모든 스레드의 경우 Stack이외의 영역은 프로세스의 영역을 공유받아 사용하게 되고 이러한 이유로 인해 스레드간 Context Switching(아래에 간단히 설명)이 발생했을 경우 Stack 영역의 데이터들만 switching되면 되므로 프로세스 스위칭보다 훨씬 빠르게 진행이 됩니다. 스레드의 장점으로는 시스템의 Throughput(처리량)이 향상 되며, 자원 소모가 줄어들고 스레드간의 스위칭 시간이 줄어들면서 일을 처리할 때 응답 시간이 단축되는 점이 있습니다. 반면에 여러 개의 스레드를 사용할 때는 프로세스가 가지고 있는 메모리 영역의 자원 공유의 문제가 발생할 수 있고 디버깅이 힘들다는 점이 있습니다. 마지막으로 프로세스의 메모리 영역(Data, heap)을 공유함으로써 전역 변수와 동적 할당 딘 메모리 공간을 공유하게 되고 이를 통해 쓰레드간 통신이 쉽게 가능하게 됩니다.


[ THREAD가 스택을 독립적으로 할당하는 이유 ]

 스택은 함수 호출 시 전달되는 인자, 되돌아갈 주소 값 및 함수 내에서 선언하는 변수 등을 저장하기 위해 사용되는 메모리 공간입니다. 따라서 스택 메모리 공간이 독립적이라는 것은 독립적인 함수 호출이 가능하다는 것이고, 이는 독립적인 실행흐름을 가질 수 있다는 것입니다. 결과적으로 실행 흐름의 추가를 위한 최소 조건이 독립된 스택을 제공하는 것이라고 볼 수 있습니다.


[ Context  Switching 이란? ]

 프로세스를 이것저것 우선 순위에 따라 변경하기 위해서는 실제로 작업에 사용되는 프로세스 데이터를 레지스터와 메모리 사이를 왕복하며 값을 복사해야 합니다. 보통 cpu에 의해 프로세스가 일을 처리하게 되는데 스케줄링 방식에 따라 특정 프로세스가 일을 진행하고 있다가 다른 프로세스에게 cpu사용권을 넘겨주게 될 때 어디까지 작업을 했고 다음부터는 어디서부터 작업을 해야하는지에 대한 정보를 보관할 수 있는 곳이 필요하고 이러한 정보들을 프로세스에 맞게 변경해주고 처리하는 것을 말합니다. 실제로 CPU는 동시에 한 개씩만 스레드를 실행시킬 수 있는데 스레드가 여러개가 생성되게 되면 CPU는 각각의 스레드를 번갈아가며 실항하게 되는데, 이 때 이전 스레드의 문맥 정보(레지스터 값, 실행중인 스택 정보 등)을 백업받고 백업 받아놓았던 다음 스레드의 문맥정보를 로딩하는 과정을 거치게 됩니다. 이 과정을 Context Switchig이라고 합니다. 이러한 스레드가 많아질 수록 Context Switching에 많은 부하가 걸리기 때문(메모리와 레지스터 사이의 데이터 이동도I/O이다)에 잘 고려해서 사용해야 되겠습니다.  


오늘 포스팅은 여기까지 하도록 하겠습니다. 잘못된 부분이나 설명이 부족한 부분은 댓글로 남겨주시면 참고하도록 하겠습니다. 감사합니다.




반응형
반응형


 

안녕하세요. 오늘은 작년 신입 교육 때, 딱 1년 전 읽었던 책 ( 열혈강의, 자바 웹 개발 워크북 )에 대해 정리해 보는 시간을 갖도록 하겠습니다. 책상 옆에 놓여있길래 막상 꺼내 펼쳐 보니 잊고 있었던 내용들도 있고 다시 한 번 상기할만한 내용들이 있어 이렇게 정리하게 되었습니다. 이제 막 웹을 시작하시는 분들이 보시기에 좋은 책인 것 같습니다. 정리라는게 챕터별로 정리하는 게 아닌 개인적으로 메모해놓고 다음에 다시 상기해 볼 만한 내용들이나 괜찮은 내용이다 싶은 부분만을 추려 정리하는 것이기 때문에 자세한 내용을 알고 싶으실 경우 책을 사서 보시길 추천해드립니다.

 

 

[ 프록시 서버 (Proxy Server) ]

클라이언트와 서버 사이에서 통신을 중계해 주는 컴퓨터나 프로그램을 말합니다. 프록시 서버의 주된 용도 중 하나는 빠른 전송을 위하여 서버의 응답 결과를 캐시에 저장해 두는 것입니다. 프록시 서버를 두는 두 번째 이유는 보안적인 부분인데, 첨단 기술을 다루는 회사의 경우 내부 사용자의 기밀 유출에 민감할 수밖에 없습니다. 이런 경우 프록시 서버를 이용하면 외부로 전달되는 데이터를 검사하여 특정 단어가 포함된 자료의 송.수신을 차단하거나 보안 팀에 경고 메시지를 보낼 수 있습니다.

 

[ 멀티 프로세스와 멀티 스레드 ]

멀티 프로세스 방식은 클라이언트가 연결 요청을 하면 서버 프로그램은 자신을 복제하여 클라이언트에 대응하게 하고, 자신은 다른 클라이언트의 요청을 기다립니다. 이 방식은 원본 프로세스의 메모리를 모두 복제하기 때문에 자원 낭비가 심합니다. 그에 비해 멀티 스레드 방식은 클라이언트 요청을 처리하는 일부 코드만 별도로 분리하여 실행하기 때문에 전체 메모리를 복제할 필요가 없어, 멀티 프로세스 방식보다 메모리 낭비가 적습니다.

 

[ 요청 헤더 ]

헤더에는 세 가지 종류가 있는데 요청이나 응답 모두에 적용할 수 있는 '일반 헤더(General-header)'와 요청 또는 응답 둘 중 하나에만 적용할 수 있는 '요청 헤더 또는 응답 헤더(Request-header/Response-header)', 보내거나 받는 본문 데이터를 설명하는 '엔티티 헤더(Entity-header)'가 있습니다. 요청 헤더가 담는 헤더명중 User-Agent가 있는데 클라이언트의 정보를 서버에게 알려주는 헤더입니다. 웹 서버는 이 헤더를 분석하여 요청자의 OS와 브라우저를 구분합니다.

 

[ CGI(Common Gateway Interface) ]

웹 서버와 프로그램 사이의 데이터를 주고받는 규칙을 CGI(Common Gateway Interface)라고 합니다. 이렇게 웹 서버에 의해 실행되며 CGI 규칙에 따라서 웹 서버와 데이터를 주고 받도록 작성된 프로그램을 'CGI 프로그램'이라고 합니다.

 

[ 서블릿 컨테이너 ]

서블릿의 생성과 실행, 소멸 등 생명주기를 관리하는 프로그램을 '서블릿 컨테이너(Servlet Container)'라 합니다. 서블릿 컨테이너(Jave EE 기술 중에서 서블릿, JSP 등 웹 관련 부분만 구현한 서버로 아파치 재단의 톰캣, Jetty등)가 서블릿을 대신하여 CGI 규칙에 따라 웹 서버와 데이터를 주고받습니다.

 

[ WebContent/Web-INF ]

웹 애플리케이션의 설정과 관련된 파일을 두는 폴더로 이 폴더에 있는 파일은 클라이언트에서 요청할 수 없다. 따라서 HTML이나 JavaScript, CSS 등 클라이언트에서 요청할 수 있는 파일을 이 폴더에 두어서는 안 됩니다.

 

[ GET 요청으로 넘어온 매개변수 값의 인코딩 설정 ]

GET 요청은 매개변수 값이 URL에 포함되기 때문에 setCharacterEncoding()으로는 문자 집합을 설정할 수 없다. 톰캣 서버에서 server.xml을 열어 <Connector>태그에 URIEncoding 속성을 추가하고, 값은 UTF-8로 설정한다. 웹 브라우저가 웹 서버로 데이터를 보낼 때는 웹 페이지의 기본 문자집합으로 인코딩하여 보내기 때문에 사용자가 입력한 값은 UTF-8로 인코딩되어 서버에 전달된다. 반면 서블릿은 UTF-8(한글 한 자를 3바이트로 표현) 3바이트를 하나의 문자로 인식하지 않고 각각의 바이트를 개별 문자로 취급하여 유니코드로 변환한다. 이렇기에 server.xml에 설정을 해주지 않을 경우 한글이 깨지게 된다.

 

[ SeverletContext 보관소 ]

웹 애플리케이션이 시작될 때 생성되어 웹 애플리케이션이 종료될 때까지 유지된다. 이 보관소에 데이터를 보관하면 웹 애플리케이션이 실행되는 동안에는 모든 서블릿이 사용할 수 있다.

 

[ HttpSession 보관소 ]

클라이언트의 최초 요청 시 생성되어 브라우저를 닫을 때까지 유지됩니다. 보통 로그인할 때 이 보관소를 초기화하고, 로그아웃하면 이 보관소에 저장된 값들을 비웁니다. 따라서 이 보관소에 값을 보관하면 서블릿이나 JSP 페이지에 상관없이 로그아웃하기 전까지 계속 값을 유지할 수 있습니다. JSP에서는 session변수를 통해 이 보관소를 참조할 수 있습니다.

 

[ ServletRequest 보관소 ]

클라이언트의 요청이 들어올 때 생성되어, 클라이언트에게 응답 할 때까지 유지됩니다. 이 보관소는 포워딩이나 인클루딩하는 서블릿들 사이에서 값을 공유할 때 유용합니다. JSP에서는 request변수를 통해 이 보관소를 참조할 수 있습니다.

 

[ JspContext 보관소 ]

JSP 페이지를 실행하는 동안만 유지됩니다. JSP에서는 pageContext 변수를 통해 이 보관소를 참조할 수 있습니다.

 

[ HttpSession ]

HttpSession 객체는 클라이언트 당 한 개가 생성됩니다. 웹 브라우저로부터 요청이 들어오면, 그 웹 브라우저를 위한 HttpSession 객체가 있는지 검사하고, 없다면 새로 HttpSession 객체를 만듭니다. 이렇게 생성된 HttpSession 객체는 그 웹 브라우저로부터 일정 시간 동안 Timeout 요청이 없으면, 삭제됩니다.

 

[ JspContext의 활용 ]

JSP 페이지를 작성하다 보면 <jsp:include>와 같은 특별한 태그를 사용하게 됩니다. 이런 태그들은 JSP 엔진이 서블릿 클래스를 생성할 때 특정 자바 코드로 변환됩니다. 이때 이 태그의 값을 다루는 객체를 '태그 핸들러'라고 부릅니다. 바로 이 태그 핸들러에게 데이터를 전달하고자 할 때 JspContext 보관소를 사용하는 것입니다.  JSP 페이지에 선언된 로컬 변수는 태그 핸들러에서 접근할 수 없습니다. 따라서 태그 핸들러에게 전달할 데이터가 아니라면 JspContext에 값을 보관할 필요가 없습니다.

 

[ EL(Expression Language) ]

EL(Expression Language)은 콤마(.)와 대괄호([])를 사용하여 자바 빈의 프로퍼티나 맵, 리스트, 배열의 값을 보다 쉽게 꺼내게 해주는 기술로 스태틱(static)으로 선언된 메서드를 호출 할 수도 있습니다. EL은 ${}와 #{}를 사용하여 값을 표현합니다. ${표현식} 으로 지정된 값은 JSP가 실행될 때 JSP 페이지에 즉시 반영됩니다. 그래서 ${}을 '즉시 적용(immediate evaluation)'이라 부릅니다. #{}을 '지연 적용(deferred evaluation)'이라 부르는데 UI를 만들 때 사용된다고 합니다.

 

[ DI(Dependency Injection) ]

작업에 필요한 객체를 외부로부터 주입 받는 것으로 다른 말로 역제어(IoC, Inversion of Control)'라고도 부릅니다.

 

[ mybatis ]

mybatis는 반복적이고 지루한 JDBC 프로그래밍을 단순화하기 위해 클린턴 비긴이 만든 작은 라이브러리에서 출발하였다. 이 라이브러리는 iBATIS라는 이름으로 2004년 아파치 소프트웨어 재단에 기부되면서 알려지게 되었다. 좀 더 효율적인 개발 관리를 목표로 2010년 6월 아파치 재단에서 구글 코드로 이사하였고 프로젝트 이름도 mybaits로 바뀌었다. mybatis의 핵심은 개발과 유지보수가 쉽도록 소스 코드에 박혀있는 SQL을 별도의 파일로 분리하는 것이다. 또한 단순하고 반복적인 JDBC 코드를 캡슐화하여 데이터베이스 프로그래밍을 간결하게 만드는 것이다.

 

[ mybatis javaType속성 ]

<result>에서 javaType을 사용하면, 칼럼의 값을 특정 자바 객체로 변환할 수 있다. 다음과 같이 'STA_DATE'칼럼에 대해 javaType을 java.sql.Date으로 설정하면, 칼럼 값을 꺼낼 때 그 객체로 변환된다.

<result column="STA_DATE" property="startDate" javaType="java.sql.Date"/>

 

[ mybatis <id> 엘리먼트 ]

SELECT 문을 실행하면 레코드 값을 저장하기 위해 결과 객체가 생성되는데, SELECT문을 실행할 때마다 매번 결과 객체를 생성한다면 실행 성능이 나빠질 것입니다. 이를 해결하기 위해 SELECT를 통해 생성된 결과 객체들은 별도의 보관소에 저장(캐싱, caching)해두고, 다음 SELECT를 실행할 때 재사용합니다. 이때 보관소에 저장된 객체를 구분하는 값으로 <id>에서 지정한 프로퍼티를 사용합니다.

 

[ mybatis의 SELECT 결과 캐싱 ]

SELECT를 실행할 때마다 결과 레코드에 대해 매번 객체를 생성한다면, 속도도 느리고 메모리도 낭비됩니다. 이를 개선하기 위해 mybatis는 객체 캐싱을 제공합니다. 즉 한 번 생성된 객체는 버리지 않고 보관해 두었다가, 다음 SELECT를 실행할 때 재사용하는 것입니다. 첫 번째 질의를 수행할 때 생성된 결과 객체는 풀(pool)에 보관해 둡니다. 두 번째 질의에서는 질의 결과에 대해 새로 객체를 생성하기 전에, 객체 풀에 보관된 객체 중에서 해당 칼럼의 값과 일치하는 객체를 먼저 찾습니다. 있다면 기존 객체를 사용하고 없다면 새로 객체를 생성합니다. 이것이 mybatis의 객체 캐싱 기법입니다.

 



반응형

+ Recent posts