Host network


네트워크를 호스트로 설정하면 호스트의 네트워크 환경을 그대로 쓸 수 있다.


# docker run -i -t --name host_ubuntu --net host ubuntu:latest


컨테이너의 네트워크를 호스트 모드로 설정하면 컨테이너 내부 앱의 별도 포트 포워딩 없이 바로 접근할 수 있다.






none network



말그대로 아무런 네트워크를 사용하지 않는 것을 뜻하며, 외부와 단절된다.


# docker run -i -t --name none_ubuntu --net none ubuntu:latest




Container network


말그대로 다른 컨테이너의 네트워크 환경을 공유한다. 이 때, 한 컨테이너는 다른 컨테이너의 네트워크 환경을 공유하므로 내부 IP를 새로 할당받지 않고 호스트의 가상 네트워크 인터페이스도 생성되지 않는다. 



# docker run -i -t --name container_ubuntu ubuntu:latest


# docker run -i -t --name container2_ubuntu --net container:container_ubuntu ubuntu:latest










간단하게 서로 다른 대역의 LAN을 연결 시켜주는 장치

OS 2계층 (데이터)에 있는 여러개의 네트워크 세그먼트를 연결한다.





https://zetawiki.com/wiki/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC_%EB%B8%8C%EB%A6%AC%EC%A7%80



브리지 네트워크


앞서 기본적으로 쓸 수 있는 네트워크 중 bridge와 host, none을 확인했다.

도커에서는 브리지 네트워크를 사용자가 구성해 docker0을 대신해 각 컨테이너에 연결할 수 있도록 지원하며, 외부와 통신할 수 있다.


다음 명령어를 통해 새로운 브리지 네트워크를 생성할 수 있다.


#docker network create --driver bridge swift-bridge


# docker run -i -t --name net_ubuntu -p 8080:8080 --net swift-bridge ubuntu:latest


# docker inspect net_ubuntu






--subnet, --ip-range,--gateway 옵션 등을 통해 추가 네트워크 설정도 할 수 있다.






--net-alist


호스트의 별칭을 생성


사용자 정의 브리지 네트워크와 run 명령어의 --net-alias 옵션을 함께 쓰면 특정 호스트 이름으로 컨테이너의 여러개 IP의 목록을 갖는다.



# docker run -i -t --name ubuntu_alias_container1 --net swift-bridge --net-alias swift ubuntu:latest


# docker run -i -t --name ubuntu_alias_container2 --net swift-bridge --net-alias swift ubuntu:latest



각각의 IP가 생성되었으며  docker 엔진에 내장된 DNS가 swift라는 host 이름의 별칭으로 생성된 컨테이너로 변환한다. 


컨테이너 실행 시 ubuntu_alias_container1과 ubuntu_alias_container2는 swift라는 이름의 호스트 이름으로 swift-bridge에 등록 했으며, 도커 내장 DNS 서버는 swift라는 호스트 이름의 IP 목록을 여러 개 들고 있다.








해당 호스트 이름으로 ping을 날려보자.

# docker run -i -t --name ubuntu_ping --net swift-bridge ubuntu:latest


# ping -c 1 swift


결과, 각 각 IP로 Ping이 전송된 것을 확인 할 수 있는데, 매 번 전달되는 ping이 달라지는 것은 DNS가 랜덤하게 순서가 바뀐 IP의 리스트를 반환하고 클라이언트는 이 중 첫번 째 IP를 사용한다.







도커의 컨테이너 IP는 수시로 재시작 혹은 변경될 요소가 있다. 도커의 DNS는 --link 옵션과 같은 호스트 이름으로 유동적으로 컨테이너를 찾을 때 주로 사용한다. 이는 컨테이너 IP가 변경되어도 별명으로 컨테이너를 찾을 수 있게 DNS에 의해 자동 관리 되는데, --link 옵션은 디폴트 브리지 네트워크의 컨테이너 DNS라는 점이 다르다.

# docker run -i -t --name ubuntu_container --link test12345:alias_ubuntu ubuntu:latest


# cat /etc/hosts







참고- https://m.blog.naver.com/PostView.nhn?blogId=alice_k106&logNo=220747224965&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F




'Cloud & NoSQL & Middleware > Docker' 카테고리의 다른 글

DockerFile (1)  (0) 2018.10.15
Docker Network (3) - host, none, container network  (0) 2018.09.18
Docker Network (1) - docker0  (0) 2018.09.14
Docker Container - 명령어 & Volume  (0) 2018.09.09
Docker Engine, image  (0) 2018.09.08

Network


도커는 컨테이너 내부 IP를 순차적으로 할당하며 컨테이너가 재시작 할 때마다 변경될 수 있다.


내부 IP는 도커가 설치된 호스트, 즉 내부망에서만 쓸 수 있는 IP이므로 외부와 연결될 필요가 있다.


도커는 컨테이너에 외부와의 네트워크를 제공하기 위해 컨테이너마다 가상 네트워크 인터페이스를 호스트에 생성하며 이 인터페이스 이름은 veth로 시작한다. veth 인터페이스는 사용자가 직접 생성하지 않아도 되며 컨테이너가 생성될 때 도커엔진에 의해 자동 생성된다.




Docker0


Docker0 브리지의  각 컨테이너의 veth 인터페이스와 바인딩되며, 호스트OS의 eth0 인터페이스와 이어주는 역할을 한다.

특징은 다음과 같다.


  • IP 는 자동으로 172.17.42.1 로 설정 되며 16 bit netmask(255.255.0.0) 로 설정된다. 
  • 이 IP는 DHCP를 통해 할당 받는 것은 아니며, docker 내부 로직에 의해 자동 할당 받는 것이다.
  • docker0 는 일반적인 interface가 아니며, virtual ethernet bridge 이다.



Docker Network 기능

도커에서 기본적으로 쓸 수 있는 네트워크는 docker network ls 명령어로 확인가능하다.


# docker network ls





기본적으로 bridge, host, none 네트워크가 있는 것 을 알 수있다. 브리지 네트워크는 컨테이너를 생성 할 때 자동으로 연결되는 docker0 브리지를 활용하도록 설정되었으며 네트워크는 172.17.0.x IP 대역을 순차적으로 할당한다.




'Cloud & NoSQL & Middleware > Docker' 카테고리의 다른 글

Docker Network (3) - host, none, container network  (0) 2018.09.18
Docker Network (2) - 브리지(bridge) network  (0) 2018.09.17
Docker Container - 명령어 & Volume  (0) 2018.09.09
Docker Engine, image  (0) 2018.09.08
Docker?  (0) 2018.09.08

Container


컨테이너는 간단히 생각하면 애플리케이션를 포함한 그릇 혹은 집 정도로 의미를 두면 될 것 같다.

컨테이너는 각자의 독립된 공간을 갖고 있으며 OS의 커널을 공유할 수 있으며 컨테이너간 영향을 주지 않으며 OS 호스트에도 영향을 주지 않는다.







명령어



1) run vs create


- 두 명령어 모두 이미지를 통해 컨테이너를 생성하는 명령어이다.

- Run 명령어는 생성과 동시에 컨테이너 내부로 접근이 가능하다.

- Create 명령어는 생성에만 관여한다. 이 후 접근하기 위해 start 와  attatch(컨테이너 내부 접근) 명령을 추가로 수행해야 한다.


ex ) Docker run -i -t --name ubuntu ubuntu:latest

ex ) Docker create -i -t --name ubuntu ubuntu:latest

       Docker start  ubuntu

       Docker attach -i -t ubuntu




일반적으로 컨테이너를 생성과 동시에 접근하기 때문에 run 명령어에 익숙해지는 것이 좋다. 형식은 다음과 같다.



docker run [옵션] [이미지] [명령] [매개변수]





자주쓰는 옵션 대해 살펴보면..


옵션 

설명 

 -i, -t

 -interactive  -tty  i와 t는 터미널 입력을 위한 옵션으로 일반적으로 -it  혹은 -i -t

 -d

 detached mode 흔히 말하는 백그라운드 모드

 --name

 컨테이너 이름 설정

 -p

 호스트와 컨테이너 포트의 연결 : 포워딩

 -e 

 컨테이너 내에서 사용할 환경변수 설정

 -rm

 프로세스 종료시 컨테이너 자동 삭제

 --link

 컨테이너 연결 [컨테이너명:별칭] 

 -v

 호스트와 컨테이너의 디렉토리 연결 (마운트) 

 -e

 컨테이너 내에서 사용할 환경변수 설정 



보다 더 자세한 사항은 docker run --help 를 통해 확인할 수 있다.


위의 옵션을 사용한 예를 사용해보면..



docker run -d -i -t -p 80:80 -p 192.168.10.1:7777:80 --name myserver --link mysql:mysql ubuntu:latest 



=> 컨테이너 생성과 동시에 내부에 접근하며 호스트 포트 80과 외부에서 접근 가능하도록 192.168.10.1:7777 포트 2개를 포워딩했으며 mysql 이름을 갖는 mysql 서버를 링크했다.


=>  우분투 컨테이너 내부에 접근해서 mysql 서버의 DNS를 확인하면 다음과 같다.







아래표는 자주 사용하는 도커 명령어에 대한 정리 사항입니다.





명령어

설명 

 run, create

 컨테이너 생성

 pull

 docker hub로부터 이미지를 내려받음

 start

 컨테이너 시작 

 stop

 컨테이너 중지 

 ps [-a]

 컨테이너 목록 확인 
 -a 옵션은 중지된 컨테이너까지 확인 

 -q 옵션은 아이디만 얻어옴


 ex) docker stop $(docker ps -a -q)  : 모든 컨테이너 중지

 ex) docker rm $(docker ps -a -q) : 모든 컨테이너 삭제


 rm

 컨테이너 삭제 

 rmi

 이미지 삭제 

 prune


 모든 컨테이너 삭제


 ex) docker container prune 

 rename

 컨테이너 이름 재지정 

 exec

 

컨테이너 내부에서 명령어를 실행한 뒤 그 결과 값을 반환


ex) docker exec -it [container] [cmd] 

 inspect

 이미지,컨테이너, 볼륨 등 도커 모든 구성단위의 세부 정보 출력 





2) 도커 볼륨 (Volume)


도커 이미지로 컨테이너를 생성하면 이미지는 읽기 전용이 되며 컨테이너의 변경사항만 별도로 각 컨테이너의 정보로 보존한다.


예를 들어 mysql 이미지의 경우 이미지에는 mysql을 실행하는데 필요한 애플리케이션 정보만 들어있고, 컨테이너를 생성하여 mysql 컨테이너에는 쓰기모드가 가능하여 여러 


데이터가 저장된다. 하지만 만일 도커 컨테이너를 삭제한다면, 컨테이너 계층의 데이터도 모두 삭제 된다. 그렇기 때문에 데이터의 영속성을 유지해야 하는데 이 때 볼륨을 통해 


쉽게 활용할 수 있다. 볼륨을 활용하는 방법은 호스트와 볼륨을 공유하거나, 볼륨 컨테이너를 활용하거나, 혹은 도커가 관리하는 볼륨을 생성할 수 있다.





[i] 호스트 볼륨 공유


docker run  -v  [호스트 공유 디렉토리] : [컨테이너 공유디렉토리] 컨테이너


ex) docker run -e MYSQL_ROOT_PASSWORD=1234 -v /Users/chul/Documents/Docker/volume:/var/lib/mysql mysql





해당 경로에 파일이 생성된 것을 확인 할 수 있다. 


혼동할 수 있는 점은 /var/lib/mysql 을 동기화 하는 것이 아닌 완전히 같은 디렉토리라는 것이다. 


호스트 디렉토리가 없다면, 생성하고 컨테이너 내부의 디렉토리는 삭제하게 된다. 


만일 컨테이너 내부에 디렉토리가 존재하고, 호스트 볼륨공유를 통해 호스트 디렉토리를 지정하면 컨테이너 디렉토리는 덮어씌워진다. (Mount)





[ii] 볼륨 컨테이너 


볼륨을 사용하는 두 번째 방법은 볼륨 컨테이너를 지정하여 공유하는 것이다.


볼륨 컨테이너는 -v, -volume 옵션을 통해 호스트 디렉토리와 공유하고 있으며, -volumes-from 옵션을 통해 컨테이너와 공유 할 수 있다.


ex) docker run --name mycontainer --volumes-from volumes_container ubuntu:latest



즉, 간접적으로 볼륨컨테이너와 연결해 데이터를 공유하는 방식이다.





[iii] 도커 볼륨



볼륨을 사용하는 세 번째 방법은 볼륨 명령어를 사용하는 것이다.


ex) docker volume create --name volume_container

 

ex) docker volume ls




ex) docker run -it --name volume_ex_server -v volume_container:/etc/ ubuntu:latest

[볼륨 이름 : 컨테이너의 공유 디렉토리]






 이 처럼 컨테이너가 아닌 외부에 데이터를 저장하고 동작하도록 stateless 하도록 설계하는 것이 바람직하다.









참고 

 

https://www.docker.com/

https://www.joinc.co.kr/w/man/12/docker/privateRepository

http://blog.naver.com/alice_k106        






'Cloud & NoSQL & Middleware > Docker' 카테고리의 다른 글

Docker Network (2) - 브리지(bridge) network  (0) 2018.09.17
Docker Network (1) - docker0  (0) 2018.09.14
Docker Engine, image  (0) 2018.09.08
Docker?  (0) 2018.09.08
Docker in MacOS 설치  (0) 2018.08.04


Engine


도커엔진에서 사용하는 기본단위는 이미지와 컨테이너이며, 두가지가 도커엔진의 핵심이다.


앞서 정리했지만, 도커엔진은 컨테이너와 이미지를 생성하고 사용하는데 필요한 기능을 제공하는 경량 런타임 도구이다.




Images


도커에서 이미지는 여러개의 계층으로 된 바이너리 파일로 존재하고, 컨테이너를 생성하고 실행할 때 읽기 전용으로 실행된다.


Format은 다음과 같이 구분된다.


[저장소 이름]/[이미지이름]:[태그]


swifty/ubuntu:14.0.4   or    swifty/ubuntu:latest



저장소 : 이미지가 저장된 장소를 의미, 도커에서 기본적으로 제공하는 이미지 저장소인 Docker Hub를 통해 우분투, CentOS와 같은 이미지를 받을 수 있으며 애플리케이션을 관리하기 위해 개인 저장소를 만들어 이미지를 관리할 수 있다. 이미지를 생성할 때 저장소 이름을 명시할 필요하는 없으므로 생략가능.


이미지 이름: 생략 불가능. 이미지의 역햘 단위로 이름을 지정


태그 : 버전관리 목적





'Cloud & NoSQL & Middleware > Docker' 카테고리의 다른 글

Docker Network (2) - 브리지(bridge) network  (0) 2018.09.17
Docker Network (1) - docker0  (0) 2018.09.14
Docker Container - 명령어 & Volume  (0) 2018.09.09
Docker?  (0) 2018.09.08
Docker in MacOS 설치  (0) 2018.08.04

Docker


- 도커는 리눅스 컨테이너에 여러 기능을 추가함으로써 애플리케이션을 컨테이너로서 좀 더 쉽게 사용할 수 있게 만들어진 오픈소스 프로젝트이다.

- Go 언어로 작성 돼 있다.

- 도커와 관련된 프로젝트는 도커 컴포즈(Compose), 레지스트리, 도커머신, Kitematic 등 여러가지가 있지만 일반적으로 도커 엔진, 도커 관련 프로젝트를 일컫는다.


- 도커는 원래 리눅스에서 작동하는데 최적화 돼 있으므로, 윈도우 혹은 MAC OS에서 사용할 경우 일부 기능의 제약이 있을 수 있다.




가상 머신과 도커 컨테이너


기존의 가상화 기술은 하이퍼바이저를 이용해 여러 개의 운영체제를 하나의 호스트에서 생성해 사용하는 방식이었다.




출처: https://devnet.kentico.com/articles/running-kentico-in-a-docker-container

(기존의 가상화 머신과 도커의 비교)




그러나 각종 시스템 자원을 가상화하고 독립된 공간을 생성하는 작업은 하이퍼 바이저를 반드시 거치기에 일반 호스트에 비해 성능 손실이 발생한다. 즉 가상 머신은 완벽한 운영체제를 생성할 수 있다는 장점은 있지만 일반 호스트에 비해 성능 손실이 있으며, 이에 따른 배포에 부담이 있을 수 있다.


반면 도커 컨테이너는 가상화된 공간을 생성하기 위해 리눅스 자체 기능인 chroot, namespace, cgroup를 사용함으로서 프로세스 단위의 격리 환경을 만들기 때문에 성능의 손실이 거의 없다. 


컨테이너에 필요한 커널은 호스트의 커널을 공유해 사용할 수 있으며, 컨테이너 안에서 사용하는 애플리케이션을 구동하는데 필요한 라이브러리 및 실행파일만 존재하기 때문에 이미지의 크기가 줄어들게 된다.


도커 컨테이너 이미지는 코드, 런타임, 시스템 도구, 라이브러리 및 설정과 같은 애플리케이션 단위의 프로그램을 실행하는데 필요한 모든 것을 포함하는 경량 소프트웨어 패키지다.


컨테이너 이미지를 생성하여 실행(Runtime)할 때 컨테이너가 생성된다. - (이미지는 도커엔진이 실행하여 컨테이너로 만들어준다.)



정리하면 도커 컨테이너의 특징은 간단하게 3가지로 구분할 수 있다.


1) Standard : 컨테이너는 표준화된 소프트웨어이기에 손쉽게 개발, 배포가 가능하다.

2) LightWeight : 컨테이너는 OS의 커널을 공유하기 때문에 애플리케이션 별 OS가 필요하지 않다. 때문에 서버효율성이 증대된다.

3) Secure : 애플리케이션은 컨테이너에서 안전하며, 도커에서 기본적으로 안정성을 제공한다.








'Cloud & NoSQL & Middleware > Docker' 카테고리의 다른 글

Docker Network (2) - 브리지(bridge) network  (0) 2018.09.17
Docker Network (1) - docker0  (0) 2018.09.14
Docker Container - 명령어 & Volume  (0) 2018.09.09
Docker Engine, image  (0) 2018.09.08
Docker in MacOS 설치  (0) 2018.08.04



JDK, JRE, JVM 그리고 메모리 구조






JDK

JDK는 자바 개발도구(Java Development Kit)의 약자이다.

JDK는 JRE 에서 개발을 위해 필요한 도구(javac, java, visualVM 등)들을 포함한다.


JRE

JRE는 자바 실행환경(Java Runtime Environment)의 약자이다.

JRE는 JVM 이 자바 프로그램을 동작시킬 때 필요한 라이브러리 파일들과 기타 파일들을 가지고 있다. JRE는 JVM의 실행환경을 구현했다고 할 수 있다.



JVM


위키에서는 JVM을 Java Byte Code를  실행하는 주체라고 정의하고 있다.

바이트 코드를 실행하는 주체의 의미는, 자바 소스코드로부터 만들어지는 자바 바이너리 파일(.class)을 실행할 수 있다는 뜻이다.

컴파일된 바이너리 코드(.class)는 어떤 JVM에서도 동작시킬 수 있게 된다.






출처: https://ko.wikipedia.org/wiki/%EC%9E%90%EB%B0%94_%EA%B0%80%EC%83%81_%EB%A8%B8%EC%8B%A0





JVM의 역할


  • 바이너리 코드를 읽는다.
  • 바이너리 코드를 검증한다.
  • 바이너리 코드를 실행한다.
  • 실행환경(Runtime Environment)의 규격을 제공한다. (필요한 라이브러리 및 기타파일)





JVM의 특징

1) 스택 기반의 가상 머신 

- 대표적인 컴퓨터 아키텍처인 인텔 x86 아키텍처나 ARM 아키텍처와 같은 하드웨어가 레지스터 기반으로 동작하는 비해 JVM 스택 기반으로 동작한다.


2) 심볼릭 레퍼런스

기본 자료형(primitive data type) 제외한 모든 타입(클래스와 인터페이스) 명시적인 메모리 주소 기반의 레퍼런스가 아니라 심볼릭 레퍼런스를 통해 참조한다.


3) 가비지 컬렉션(garbage collection)

 - 클래스 인스턴스는 사용자 코드에 의해 명시적으로 생성되고 가비지 컬렉션에 의해 자동으로 파괴된다.

4) 기본 자료형을 명확하게 정의하여 플랫폼 독립성 보장

- C/C++ 등의 전통적인 언어는 플랫폼에 따라 int 형의 크기가 변한다. JVM 기본 자료형을 명확하게 정의하여 호환성을 유지하고 플랫폼 독립성을 보장한다


5) 네트워크 바이트 오더(network byte order)

자바 클래스 파일은 네트워크 바이트 오더를 사용한다. 인텔 x86 아키텍처가 사용하는 리틀 엔디안이나, RISC 계열 아키텍처가 주로 사용하는 엔디안 사이에서 플랫폼 독립성을 유지하려면 고정된 바이트 오더를 유지해야 하므로 네트워크 전송 시에 사용하는 바이트 오더인 네트워크 바이트 오더를 사용한다. 네트워크 바이트 오더는 엔디안이다.



=> 많은 자바 개발자들이 알고 있는 메모리 할당과 해제를 알아서 수행해주는 가비지 컬렉터와 플램폼에 의존성 즉, JVM을 구성할 수 어느 플램폼에서든지 이식할 수 있다는 특징은 JVM의 가장 큰 장점일 것이다. 개인적으로 네트워크 프로그래밍을 하는 개발자라면, 자바언어는 빅 엔디안을 따른다는 것 쯤은 알고 있어야한다.






JVM
 수행과정



자바 컴파일러에 의해 컴파일된 클래스 파일을 JVM의 클래스로더에 의해 Runtime Data Areas(런타임 데이터 영역)에 적재하고, 실행엔진이 자바 바이트 코드를 실행시킨다.


여기서 흔히 알고 있는 특징인 자바 바이트 코드는 컴파일 시점이 아닌, Excution Engine에 의해 런타임(실행)시점에 실행된다는 점이 바로 위의 과정을 통해 알 수 있다.






Runtime Data Areas


런타임 데이터 영역은 JVM이 운영체제 위에서 실행되면서 할당받는 메모리 영역, 우리가 알고 있는 자바의 메모리 영역이다.




런타임 데이터 영역은 6개의 영역으로 나누어 지는데 , PC Register와 Stack, Native Method stack 은 쓰레드마다 차지 하는 영역이며 Heap, Method Area, Runtime Constant Pool 영역은 모든 쓰레드가 공유하는 영역이다.



1) PC 레지스터


- PC(Program Counter) 레지스터는 스레드마다 하나씩 존재하며 스레드가 시작될 생성된다. PC 레지스터는 현재 수행 중인 JVM 명령의 주소를 갖는다.


2) JVM Stack


- JVM Stack은  스레드마다 하나씩 존재하며 스레드가 시작될 생성된다. 스택 프레임(Stack Frame)이라는 구조체를 저장하는 스택으로, JVM 오직 JVM 스택에 스택 프레임을 추가하고(push) 제거하는(pop) 동작만 수행한다. 예외 발생 printStackTrace() 등의 메서드로 보여주는 Stack Trace 라인은 하나의 스택 프레임을 표현한다.


3) Native Method Stack


자바 외의 언어로 작성된 네이티브 코드를 위한 스택이다. , JNI(Java Native Interface) 통해 호출하는 C/C++ 등의 코드를 수행하기 위한 스택으로, 언어에 맞게 C 스택이나 C++ 스택이 생성된다.


4) Method Area (= Class Area, Static Area)


메서드 영역은 모든 스레드가 공유하는 영역으로 JVM 시작될 생성된다. JVM 읽어 들인 각각의 클래스와 인터페이스에 대한 런타임 상수 , 필드와 메서드 정보, Static 변수, 메서드의 바이트코드 등을 보관한다. 메서드 영역은 JVM 벤더마다 다양한 형태로 구현할 있으며, 오라클 핫스팟 JVM(HotSpot JVM)에서는 흔히 Permanent Area, 혹은 Permanent Generation(PermGen)이라고 불린다. 메서드 영역에 대한 가비지 컬렉션은 JVM 벤더의 선택 사항이다.


- 위의 말이 어려운데 한 마디로 정의하면 컴파일된 클래스파일의 자바 바이트 코드의 모든 데이터가 올라가는 영역이다. 포함되는 범위는 전역 변수, 메서드 정보, static 자료형이 붙은 필드와 메소드 등등 이며 모든 쓰레드가 공유하는 Method area에 올라가기 때문에 어느 쓰레드에서든지 클래스 내의 메소드 혹은 전역 변수 값에 접근할 수 있는 것이다.



5) Runtime Constant Pool


- 클래스 파일 포맷에서 constant_pool 테이블에 해당하는 영역이다. 메서드 영역에 포함되는 영역이긴 하지만, JVM 동작에서 가장 핵심적인 역할을 수행하는 곳이기 때문에 JVM 명세에서도 따로 중요하게 기술한다. 클래스와 인터페이스의 상수뿐만 아니라, 메서드와 필드에 대한 모든 레퍼런스까지 담고 있는 테이블이다. , 어떤 메서드나 필드를 참조할 JVM 런타임 상수 풀을 통해 해당 메서드나 필드의 실제 메모리상 주소를 찾아서 참조한다.



6) Heap

인스턴스 또는 객체를 저장하는 공간으로 가비지 컬렉션 대상이다. JVM 성능 등의 이슈에서 가장 많이 언급되는 공간이다. 구성 방식이나 가비지 컬렉션 방법 등은 JVM 벤더의 재량이다.






Class Loader


- 위에서도 언급했지만, 자바는 컴파일 시점이 아닌 런타임 시점에 클래스를 처음으로 참조하며 해당 클래스를 로드하고 링크하는 동적 로드의 특성을 갖고 있다. 이 동적로드를 담당하는 부분이 JVM의 클래스 로더이다.


- 클래스로더의 특징은 다음과 같다.



1) 계층 구조: 클래스 로더끼리 부모-자식 관계를 이루어 계층 구조로 생성된다. 최상위 클래스 로더는 부트스트랩 클래스 로더(Bootstrap Class Loader)이다.

2) 위임 모델: 계층 구조를 바탕으로 클래스 로더끼리 로드를 위임하는 구조로 동작한다. 클래스를 로드할 때 먼저 상위 클래스 로더를 확인하여 상위 클래스 로더에 있다면 해당 클래스를 사용하고, 없다면 로드를 요청받은 클래스 로더가 클래스를 로드한다.

3) 가시성(visibility) 제한: 하위 클래스 로더는 상위 클래스 로더의 클래스를 찾을 수 있지만, 상위 클래스 로더는 하위 클래스 로더의 클래스를 찾을 수 없다.

4) 언로드 불가: 클래스 로더는 클래스를 로드할 수는 있지만 언로드할 수는 없다. 언로드 대신, 현재 클래스 로더를 삭제하고 아예 새로운 클래스 로더를 생성하는 방법을 사용할 수 있다.





Class Loader 우선순위


Bootstrap > Extention > System







클래스로더가 로드를 요청받으면, 클래스 로더 캐시 상위 클래스 로더 자기 자신 순서로 클래스가 있는지 확인한다

부트 스트랩 클래스로더까지 확인해도 없으면 요청받은 클래스 로더가 파일 시스템에서 해당 클래스를 찾는다.


1) BootStrap ClassLoader

- JVM이 실행될때 가장 먼저 실행되는 클래스 로더로, 자바 실행에 필요한 기본적은 클래스를 로딩한다.

- 다른 클래스로더와 달리 네이티브 코드로 구현되어 있다.


2) Extention ClassLoader

- 추가로 로딩되는 클래스로더로 별도로 클래스패스에 설정되어 있지 않아도 로딩된다.

- 다양한 보안 확장 기능을 여기서 로드한다.


3) System ClassLoader

- ClassPath에 정의 되어 있거나 JVM옵션에서 -cp, -classpath에 지정된 클래스들이 로딩된다.

- 시스템 클래스로더는 애플리케이션의 클래스들을 로드한다고 할 수 있다.

- 즉 사용자가 지정한 $CLASSPATH내의 클래스가 로드된다.



4) User-Defined Class Loader

- 애플리케이션 사용자가 직접 코드 상에서 사용하는 클래스 로더이다.

- 일반적으로 Jar 혹은 WebApp의 경우 War로 압축된 ClassPath의 Binary Code를 사용자 정의 클래스 로더가 로드한다.





클래스 로더가 로드하지 않은 클래스를 찾으면 다음과 같은 과정을 통해 로드하고 링크하며 초기화한다.






1) 로드: 찾은 클래스 파일을 Runtime Data Area에 로드한다.

2) 검증: 읽어 들인 클래스가 제대로 구성되어 있는지 검사한다. 클래스 로드 전 과정 중 가장 시간이 오래 걸리며 까다로운 검증을 거친다.

3) 준비: 클래스가 필요로 하는 메모리를 할당하고, 클래스에 정의된 필드, 메소드, 인터페이스들을 나타내는 데이터 구조를 준비한다.

4) 분석: 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경한다. ( 심볼릭 레퍼런스는 메모리 번지의 참조를 의미하는 것이 아니라 이름에 의한 참조를 의미)

5) 초기화: 클래스 변수들을 적절한 값으로 초기화한다.













참고 : 

- https://d2.naver.com/helloworld/1230

- https://ko.wikipedia.org/wiki/%EC%9E%90%EB%B0%94_%EA%B0%80%EC%83%81_%EB%A8%B8%EC%8B%A0

- https://docs.oracle.com/javase/8/docs/technotes/guides/vm/index.html

http://yoyojyv.tistory.com/48










'JVM Optimization &Tuning' 카테고리의 다른 글

Minor GC , Major GC, Full GC  (0) 2019.12.26
GC 튜닝이 불필요한 상황  (0) 2019.12.26
JVM Heap 영역  (0) 2019.02.27

+ Recent posts