기술

프레임워크와 라이브러리의 차이점, 패킷과 라우팅, JVM 메모리 구조

leatherjean 2018. 10. 31. 04:10
프레임워크&라이브러리&패킷&라우팅&JVM

프레임워크와 라이브러리의 차이점

: 자동차와 망치라고 표현하면 편하다고 한다. 자동차는 특정 목적으로 만들어져서 목적지로 빠르게 갈 수 있는 역할만 하지만, 망치는 두드린다는 행위 하나로 사람을 때릴때도 쓸 수 있고, 못질을 할 때 쓸수있고 필요에 따라 갖다가 쓸 수 있다. 자동차를 가지고 삽질을 할 수 없고 무언가를 두들길 수도 없다. 그저 목적지까지 빠르게 데려다주는 수단일 뿐이다. 만들어질 때부터 이러한 용도로 만들어졌기 때문에 그렇다. 메뉴얼대로 조작하면 최고의 효율로 목적지까지 데려다주는게 프레임워크다. 하지만 망치는 용도에 따라 여러가지 형태로 쓰일 수 있다. 정말 잘 비유해 놓은 것 같다. 즉 프레임워크는 라이브러리와는 다르게 프로그래밍 규칙이 이미 정해져있는 것이다. 재엽님은 여기서 한 발 더 나아가서 언어를 배우는 것은 어떻게 비유할 수 있을 것인가? 에 대한 물음을 던지셨고, 스스로 사지를 움직일 수 있게 하는 것이라고 정의 내리셨다. 더 나아가서 토비의 스프링을 보면 좋은 구절이 나온다고 한다. 프레임워크는 제어의 역전이 적용된 좋은 예이고, 애플리케이션 코드가 프레임워크라는 것에 의해 사용되고,

 

 

패킷과 라우팅

: 패킷은 네트워크 상에서 데이터를 전송할 때 담아서 보내는 작은 그릇같은 용도라고 생각하면 된다. 데이터를 패킷으로 쪼개서 전송할 때의 장점은 에러가 난 부분을 찾고 그 부분만 다시 전송하기가 쉽다는 것이다. 이것을 보고 패킷 스위칭이라고 하는데, 패킷에는 헤더와 데이터 그리고 테일이 있다. 헤더에는 송신, 수신 주소 같은게 들어있고 데이터에는 데이터, 테일에는 에러메시지가 들어있다. 기존의 서킷 방식에서는 통신이 끊기면 데이터가 다 날아가서 전부 다 다시 보내야했지만, 패킷 방식에서는 유실된 패킷만 다시 요청해서 받으면 된다. 그래서 인터넷은 이런 패킷 방식을 사용한다. 하지만 패킷에는 고유 번호가 기록되어있고, 보내는 사람과 받는 사람이 순서를 지켜야하기 때문에 단점이 있다. 이런 점을 극복해내기 위해 프로토콜(규약)이 등장한 것이다.

라우팅은 네트워크 상에서 한 노드가 목적지까지 갈 수 있는 최적의 경로를 설정하는걸 말한다. 라우팅에는 정적 라우팅, 동적 라우팅이 있는데, 정적 라우팅은 목적지까지 가는 경로를 모두 입력해주어서 별다른 연산없이 빠르게 도착 가능하다. 그러나 대규모 네트워크, 예를 들면 인터넷과 같은 환경에서는 주소들이 자주 변경되므로 정적 라우팅을 쓰기에는 한계가 있다. 정적 라우팅은 네트워크 주소의 변경이 적은 곳에서 사용하는게 바람직하다. 동적 라우팅은 목적지만 명시하고 가는 경로는 라우터에게 맡긴다. 라우터는 주변 라우터 기기들과 정보를 주고 받으면서 목적지까지 가는 경로를 찾는다. 이러한 작업에 CPU 연산이 들어가고 추가적인 메모리 등이 소모된다. 그러나 동적 라우팅은 인터넷과 같이 주소가 자주 변경되는 환경에서 별다른 목적지 설정없이 자동으로 찾아가기 때문에 많이 쓰인다.

 

 

JVM 메모리 구조 파헤치기

: JVM의 메모리에는 크게 세가지 영역이 있다. 클래스 영역(보통 메소드 영역이라고 하지만 나는 클래스 영역이 더 이해하기 쉽다), 스택 영역, 힙 영역이다. 클래스 영역은 말 그대로 클래스가 로드되는 메모리이다. 클래스가 로드될 때 static으로 선언된 필드가 있다면 같이 올라간다. 그리고 클래스는 맨 처음 호출 될 때 메모리에 로드되며, 그 전에는 로드되지 않는다. 클래스가 맨 처음 호출되면 JVM은 JRE 라이브러리에서 해당 클래스를 찾고, 해당 클래스가 없으면 CLASSPATH로 설정된 곳에 방문하여 클래스를 찾는다. 찾고 난 뒤에는 바이트 코드를 비교하여 해당 클래스가 맞는지 확인하고, 메모리에 로드시켜서 JVM이 종료되기 전에는 메모리 해제가 되지 않는다.

스택 영역은 자료구조 스택과 기능이 똑같다. 먼저 들어간 녀석이 더 나중에 나오는 구조다. 스택 영역에는 메소드 호출 시 파라미터와 지역변수가 메모리에 자리를 잡게 된다. 그리고 메소드 호출이 끝나면 동시에 메모리가 해제된다. 메소드 내부의 루프나 if문 같은 경우에도 스택 영역에 쌓였다가 구간을 지나면 해제되는 형식인듯하다.

힙 영역은 GC와도 관련이 있어서 가장 까다로운 부분이다. 자바는 C와 C++처럼 포인터 개념이 없다. 따라서 new로 새로운 객체를 생성하고 변수로 그것을 참조하게 하는데, 이것을 레퍼런스라고 한다. 많은 사람들이 이것이 포인터와 똑같다고 생각하는데, 포인터는 메모리에 직접 접근할 수 있어서 Low level 개발도 가능하지만, Java의 레퍼런스는 메모리 기반이 아닌 해쉬코드 기반이다. 즉 해당 객체에 주어진 고유한 해쉬코드를 참조하는 것이다. 그러므로 Java에서는 수동으로 메모리 해제가 불가능하다. 메모리에 접근이 불가능하기 때문이다. 따라서 객체를 참조하고있던 레퍼런스가 새로운 객체를 참조하게 되면, 기존의 객체는 자신을 참조하는 레퍼런스가 없어졌으므로 메모리 상에서 갈피를 잃는다. 그렇게 되면 GC가 이 녀석을 처리하러 등장해서 메모리 해제를 자동으로 시켜준다. (추가적인 궁금증 : 객체 자신을 참조하는 레퍼런스가 없다는걸 어떻게 알 수 있을까? 라인 면접에서 질문을 봤던 것 같은데 기억이 나질 않는다. 싱글톤 객체를 생성했던 것 같은데)