자바 프로그램의 개발과 구동
현실 세계 | 가상 세계(자바 월드) | |
소프트웨어 개발 도구 | JDK - 자바 개발 도구 | JVM용 소프트웨어 개발 도구 |
운영체제 | JRE - 자바 실행 환경 | JVM용 OS |
하드웨어 - 물리적 컴퓨터 | JVM - 자바 가상 기계 | 가상의 컴퓨터 |
JVM(Java Virtual Machine)이란?
- 말그래도 '가상기계'다.
- 현실 세계에서 컴퓨터를 구동하기 위해 하드웨어와 운영체제, 소프트웨어, 스프트웨어를 개발할 수 있는 개발 도구가 필요하다.
- 자바의 가상 세계는 현실 세계를 그대로 모방한다.
JDK(소프트웨어 개발 도구)를 이용해 개발된 프로그램은
JRE(자바용 OS)에 의해
JVM(자바 가상의 컴퓨터) 상에서 구동된다.
- 배포용은 편의를 위해 JDK가 JRE를 포함함. 다시 JRE가 JVM을 포함함.
객체지향 프로그램의 메모리 사용방식
코드 실행 영역 | Stactic 영역 - 클래스들의 놀이터 | |
스택 영역 - 메서드들의 놀이터 | 힙 영역 - 객체들의 놀이터 |
다시 보는 main() 메서드: 메서드 스택 프레임
public class Start1 {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
- JRE는 먼저 프로그램 안에 main() 메서가 있는지 확인한다.
- main() 메서드의 존재가 확인되면 JVM(가상기계)에 전원을 넣어 부팅한다.
- 부팅된 JVM은 목적 파일을 받아 그 목적 파일을 실행한다.
- -> JVM이 맨 먼저 하는 일: '전처리 과정'
java.lang
- java.lang = 모든 자바 프로그램이 반드시 포함하게 되는 패키지
- JVM은 java.lang 패키지를 T 메모리의 stactic 영역에 가져다 놓는다.
- java.lang 패키지가 있어 System.out.println() 같은 메서드 실행이 가능하다.
- 클래스와 임포트 패키지를 T 메모리 Stactic 영역에 배치한 모습
main() 메서드 실행 전, JVM에서 수행하는 전처리 작업들
- java.lang 패키지를 T메모리의 stactic 영역에 배치한다.
- import된 패키지를 T 메모리의 stactic 영역에 배치한다.
- 프로그램 상의 모든 클래스를 T 메모리의 stactic 영역에 배치한다.
main() 메서드가 실행되기 위해 스택 프레임(stack frame)이 스택 영역에 할당된다.
- 클래스 정의를 시작하는 여는 중괄호를 제외하고,
- 여는 중괄호를 만날 때마다 스택 프레임이 하나씩 생긴다.
스택 프레임 - 변수 공간 할당
- 메서드의 인자 args를 저장할 변수공간을 스택 프레임의 맨 밑에 확보해야 한다.
- 이는 메서드 인자(들)의 변수 공간을 할당하는 것이다.
- 위의 그림처럼 T메모리를 구성하고 나서야 main() 메서드 안의 첫 명령문을 실행하게 된다.
[JRE-JVM의 과정]
- JRE는 눈에 보이지 않게 뒤에서 JVM이라고 하는 자바 가상 기계를 부팅한다.
- JVM은 메모리 구조를 만들고 - java.lang 패키지 로딩, 각종 클래스 로딩, main() 메서드 스택 프레임 배치, 변수공간 배치 등등의 일을 처리한다.
- 닫는 중괄호를 만나면 스택 프레임이 소멸된다.
- main() 메서드가 프로그램의 시작이면서 끝이다.
- main() 메서드가 끝나면 JRE는 JVM을 종료하고, JRE 자체도 운영체제 상의 메모리에서 사라진다.
- 그럼 이제 T메모리도 그 운명을 다하고 사라지게 된다.
핵심 키워드
# T메모리 구조, javalang패키지, import 패키지와 클래스들, 메서드 스택프레임, JVM, JRE
변수와 메모리: 변수! 너 어디 있니?
1 public class Start2 {
2 public static void main(String[] args) {
3 int i;
4 i = 10;
5
6 double d = 20.0;//6번째 줄
7 }
8 }
6번째 줄을 실행한 후의 T 메모리의 상태
7번째 줄의 실행
- 7번째 줄의 닫는 중괄호로 main() 메서드 스택 프레임이 스택 영역에서 사라진다.
- 즉, 프로그램이 종료된다.
블록 구문과 메모리: 블록 스택 프레임
if-else 구문
1 public class Start3 {
2 public static void main(String[] args) {
3 int i = 10;
4 int k = 20;
5
6 if(i = 10) {
7 int m = k + 5;
8 k = m; // 8번째 줄 실행
9 } else { // 9번째 줄 실행
10 int p = k + 10;
11 k = p;
12 }
13
14 //k = m + p;
15 }
16 }
8번째 줄 실행
6 if(i = 10) {
7 int m = k + 5;
8 k = m;
9번째 줄 실행
9 } else {
-> if문의 스택프레임이 날아가면서 지역변수가 사라졌다.
지역 변수와 메모리: 스택 프레임에 갇혔어요!
변수의 위치는 스태틱/스택/힙 영역 중 어디에 있을까?
- 정답: '세 군데 모두'에 존재한다.
- 그런데, 세 군데 각각에 있는 변수는 각기 다른 목적을 가진다.
- 각각의 이름도 지역 변수, 클래스 멤버 변수, 객체 멤버 변수로 다르다.
지역 변수
- 스택 영역에서 일생을 보낸다.
- 그것도, 스택 프레임 안에서.
- 따라서 스택 프레임이 사라지면 함께 사라진다.
- 외부 스택 프레임에서 내부 스택 프레임의 변수에 접근하는 것은 불가능하나, 그 역은 가능하다.
- 내부 스택 프레임 -> 외부 스택 프레임 🅾️
클래스 멤버 변수
- 스태틱 영역에서 일생을 보낸다.
- 스태틱 영역에 한번 자리 잡으면 JVM이 종료될 때까지 고정된(static) 상태로 그 자리를 지킨다.
객체 멤버 변수
- 힙에서 일생에서 보낸다.
- 객체 멤버 변수들은 객체와 함께 가비지 컬렉터라고 하는 힙메모리 회수기에 의해 일생을 마치게 된다.
메서드 호출과 메모리: 메서드 스택 프레임 2
메서드 호출 시, 전달되는 것
- 메서드를 호출하면서 인자로 전달되는 것은 변수 자체가 아니라 변수가 저장한 값만을 복제해서 전달한다.
- 이런 전달 방식을 Call By Vahie(값에 의한 전달)이라고 한다.
전역 변수와 메모리: 전역 변수 쓰지 말라니까요!
1 public class Starts {
2 static int share;
3
4 public static void main(String[] args) {
5 share = 55;
6
7 int k = fun(5,7);// 7번째 줄
8
9 System.out.printIn(share);
10 }
11
12 private static int fun(int m, int p) {
13 share = m + p; // 12번째 줄
14
15 return m - p;
16 }
17 }
13번째 줄
-> m+p 공격에도 꿈쩍도 않는 share = 12 ..
- 스택 프레임에 종속적인 지역 변수
7번째 줄
-> stactic 아니면 k는 이렇게 할당이 잘 된다. (가변)
- 스택 프레임에 독립적인 전역 변수
전역 변수 언제 쓰지 말고, 언제 써야 할까?
- 전역 변수의 무시무시함이 드러난다. 전역 변수를 피할 수 있다면 피해야 할 존재다.
- 다만, 읽기 전용으로 값을 공유해서 전역 상수로 쓰는 것은 적극 추천한다.
멀티 스레드 / 멀티 프로세스의 이해
멀티 스레드(Multi Thread)란?
- 멀티 스레드의 T 메모리 모델은 스택 영역을 스레드 개수만큼 분할해서 쓴다.
스태틱 영역 - 클래스들의 놀이터 | ||
스택 영역 - 메서드들의 놀이터 | 힙 영역 - 객체들의 놀이터 | |
스레드 | 스레드 |
- 하나의 T 메모리만 사용하는데, 스택 영역만 분할해서 사용하는 구조다.
멀티 프로세스(Multi Process)란?
- 다수의 데이터 저장 영역, 즉 다수의 T 메모리를 갖는 구조다.
- 멀티프로세스는 각 프로세스마다 각자의 T메모리가 있다.
- 각자 고유의 공간이므로 서로 참조할 수 없다.
자바 웹 프로그래밍의 특징: 서블릿은 요청당 스레드O(프로세스X)를 생성한다.
- 왜? 요청당 스레드(Servlet)가 요청당 프로세스(CGI, Common Gateway Interface)보다 더 효율적이기 때문이다.
- CGI는 요청당 새로운 프로세스를 생성 → 프로세스 생성/종료 비용이 크고 메모리 낭비 심함.
- 서블릿은 요청당 새로운 스레드를 생성 → 스레드는 프로세스보다 가볍고 빠름, 자원을 효율적으로 사용.
- 서블릿 컨테이너(Tomcat)는 Thread Pool을 활용 → 불필요한 스레드 생성을 방지하고 재사용하여 성능 최적화.
- 결론적으로, 서블릿 방식이 고성능 웹 애플리케이션 개발에 더 적합함.
멀티 스레드에서의 전역 변수 사용 문제점
- 예시
- 스레드1 - 공유 영역(스태틱과 힙)에 있는 전역 변수 A에 10을 할당 (static int num = 10;)
- CPU 사용권이 스레드2로 넘어감.
- 스레드2 - 전역 변수 A에 20을 할당 (num = 20;)
- CPU 사용권이 스레드1로 넘어감. A의 값을 출력
- 스레드1 입장: 갑자기 ' 20 '이 출력되네?!
- 이래서 전역 변수를 쓰지 말라는 것이다!
- 쓰기 가능한 전역 변수를 사용하게 되면 스레드 안정성이 깨진다.
- 물론, 보완하는 방법으로 락(lock)을 거는 방법이 있다.
- 그러나, 락을 거는 순간 멀티 스레드의 장점은 버린 것과 같다.
'Development > CS' 카테고리의 다른 글
[스프링 입문을 위한 자바 객체지향의 원리와 이해] 3장. 자바와 객체지향(추상화, 상속) (1) | 2025.02.27 |
---|---|
[JAVA - 면접 대비] 자바와 절차적/구조적 프로그래밍 (0) | 2025.02.14 |
[자료구조] 트라이(Trie) (0) | 2025.02.08 |
[면접을 위한 CS 전공 지식 노트] 5장. 자료구조 (0) | 2025.01.29 |
클러스터 인덱스(Clustered Index)와 넌클러스터 인덱스(Non-Clustered Index) (0) | 2025.01.24 |