자바 프로그램의 개발과 구동
현실 세계 | 가상 세계(자바 월드) | |
소프트웨어 개발 도구 | JDK - 자바 개발 도구 | JVM용 소프르웨어 개발 도구 |
운영체제 | JRE - 자바 실행 환경 | JVM용 OS |
하드웨어 - 물리적 컴퓨터 | JVM - 자바 가상 기계 | 가상의 컴퓨터 |
- JDK < JRE < JVM
- Write Once Run Everywhere
- JVM이 중재자로서 각 플랫폼(윈도우, 유닉스, 리눅스 등)에서 프로그램을 구동하게끔 해줌
기계어를 포함한 모든 프로그래밍 언어의 메모리 사용 방식
코드 실행 영역 | 데이터 저장 영역 |
객체지향 프로그래밍 언어의 메모리 사용 방식
코드 실행 영역 | 스태틱 (static) 영역 |
|
스택 (stack) 영역 | 힙(Heap) 영역 |
자바에 존재하는 절차적 / 구조적 프로그래밍의 유산
- 함수 - 중복 코드 관리, 이해하기 쉬운 코드
- 공유 사용시 문제가 발생하기 쉬운 전역 변수보다 지역변수 사용
- 함수 = 메서드
main() 메서드 : 메서드 스택 프레임
스태틱 (static) - 클래스들의 놀이터 |
|
스택 (stack) - 메서드들의 놀이터 | 힙(Heap) - 객체들의 놀이터 |
- JRE는 프로그램 안 main() 메서드 있는지 확인하고, 클래스에서 main() 메서드 발견하고 프로그래밍 실행 사전 준비 착수
- JRE는 JVM에 전원을 넣어 부팅
- 부팅된 JVM은 목적 파일을 받아 실행 = 전처리 과정
- JVM은 java.lang패키지를 T메모리의 스태틱 영역에 가져다 놓는다
- JVM은 개발자가 작성한 모든 클래스와 import 클래스역시 스태틱 영역에 가져다 놓는다.
- main()메서드가 끝나면 JRE는 JVM을 종료하고, JRE자체도 운영체제 상의 메모리에서 사라진다
변수와 메모리
public class Start2 {
public static void main(String[] args){
int i;
i=10;
double d = 20.0;
}
}
java.lang / start2 - main(args:string[]) | |
main() 스택프레임 d 20.0 i 10 args |
위 코드를 실행한 T 메모리 상태이고, i는 변수 선언의 명령문과 변수에 값을 할당하는 명령의 두개의 명령문이다.
public class Start2 {
public static void main(String[] args){
int i =10;
int k= 20;
if(i==0){
int m = k+5;
k = m;
}else{
int p = k+10;
k=p;
}
}
}
java.lang / start2 - main(args:string[]) | |
main() 스택프레임 if(true) 스택프레임 d 20.0 i 10 args |
- if문, 참인 블록의 스택 프레임만 생성된다
- m=k+5 구문은 스택 프레임 안의 변수 m에 값을 할당한다. 이때 if 스택 프레임 밖에 있으면서 main() 메서드 스택 프레임 안에 있는 k변수를 연산에 참여시킨다
- if 블록 중 참일 때의 블록을 종료하면 if 블록 스택 프레임은 스택 영역에서 사라진다
- if 블록 스택 프레임 수행중, if 블록 스택 프레임 외부에 존재하는 변수에 접근이 가능하다 = 메모리 상에 변수 k가 존재하므로
- 내부 스택 프레임에서 외부 스택 프레임의 변수에 접근이 가능하다
- 스택 메모리 내의 스택 프레임안의 변수를 지역변수라고 하며, 그 지역이 사라지면 지역변수도 메모리에서 사라진다.
지역변수와 메모리
지역변수 | 스택(stack) 영역의 스택 프레임 안에서 일생을 보내며, 스택 프레임이 사라지면 소멸된다. |
클래스 멤버 변수 | 스태틱(static) 영역에서 일생을 보낸다. 스택 영역에 한번 자리를 잡으면 jvm이 종료될때까지 고정된(static) 상태로 그 자리를 지킨다 |
객체 멤버 변수 | 힙(heap) 영역에서 일생을 보내며, 객체 멤버 변수들은 객체와 함께 가비지컬렉터(gc) 대상이다 |
메서드 호출과 메모리 : 메서드 스택 프레임2
public class Start2 {
public static void main(String[] args){
int k= 5;
int m;
m = square(k);
}
private static int square(int k) {
int result;
k= 25;
result= k;
return result;
}
}
- main() 메서드 가진 변수 k와 square() 메서드가 가진 변수 k가 이름만 같지만 실제로는 별도의 변수 공간이다 = call by value
- square() 메서드 안의 k변수에 무슨 짓을 하더라도 main()메서드 안의 k변수는 영향이 없다.
java.lang / start2 - square(k:int) main(args:string[]) | |
square() 스택프레임 result 25 k 5 반환값 25 main() 스택프레임 m ? k 5 args |
-> return result; 까지 실행한 후 T 메모리
java.lang / start2 - square(k:int) main(args:string[]) | |
main() 스택프레임 m 25 k 5 args |
-> m = sqauare(k); 까지 실행한 후 T 메모리
- 메서드 스택 프레임안에서 다른 메서드 스택 프레임의 내부 변수는 접근 불가
- main()에서 square()의 지역변수 접근불가, square()에서 main()의 지역변수 접근불가
- 입력 값들(인자 리스트)과 반환값에 의해서만 메서드 사이에서 값이 전달될 뿐 서로 내부 지역 변수 볼수 없음
- m = square(k); 실행전 까지는 T메모리 상에 square() 메서드 스택 프레임은 존재하지 않기에 square() 메서드 내의 지역변수도 존재하지 않고, 존재하지 않기에 당연히 접근 불가
- 서로 다른 메서드의 지역변수를 참조할 수 없는 이유
- 메서드는 고유 공간인데 서로 침범하면 자바 월드에 문제를 유발할 가능성
- 포인터문제로, 서로 다른 메서드에서 지역변수에 접근한다면 위치를 정확히 알아야하는데, 그를 위해서는 변수의 메모리 위치= 포인터(메모리 주소값)을 알아야하지만, 자바에는 포인터가 없음
- 메서드를 호출할 때마다 해당 메서드의 스택 프레임이 생기고, 여러번 square()를 호출시 매번 square() 스택 프레임이 생성되고 소멸된다. 이전에 만들어진 square() 메서드 스택 프레임 내 지역 변수는 다시 만들어진 square() 메서드 스택 프레임의 변수와는 완전히 별개다
- call by value = 값에 의한 전달
- 메서드를 호출하면서 인자로 전달되는 것은 변수 자체가 아닌 변수가 저장한 값만을 복제해서 전달한다
전역 변수와 메모리
public class Start2 {
static int share;
public static void main(String[] args){
share=55;
int k= fun(5,7);
}
private static int fun(int m, int p) {
share = m+p;
return m-p;
}
}
java.lang / start2 share 55 - fun(m:int, p:int) main(args:string[]) | |
fun() 스택프레임 p 7 m 5 반환값 ? main() 스택프레임 k ? args |
-> private static int fun(int m, int p) 실행한 후의 T메모리
- share = m+p를 실행하면, share은 12가 된다.
java.lang / start2 share 12 - fun(m:int, p:int) main(args:string[]) | |
fun() 스택프레임 p 7 m 5 반환값 -2 main() 스택프레임 k ? args |
-> return m-p 실행한 후의 T메모리
java.lang / start2 share 12 - fun(m:int, p:int) main(args:string[]) | |
main() 스택프레임 k -2 args |
-> int k = fun(5,7) 실행한 후의 T메모리
전역 변수
- 메서드 밖에서 선언된 변수 share는 메서드들 사이에서 공유해서 사용할 수 있는 전역변수다
- 스텍 프레임에 독립적이다.
- 다른 메서드에 의해 전역변수가 저장된다면, 코드를 추적해야만하는 유지보수의 어려움이 존재한다.
- 읽기 전용으로 값을 공유해 전역 상수로 쓰는 것은 추천
지역 변수
- 스텍 프레임에 종속적이다.
멀티 스레드
스태틱 영역 |
||
스택 (stack) 영역 |
힙(Heap) 영역 | |
스레드 | 스레드 |
- T 메모리 모들은 스택 영역을 스레드 개수만큼 분할해서 쓰는 것이다.
- 하나의 T메모리만 사용하는데 스택 영역만 분할하므로, 하나의 스레드에서 다른 스레드의 스택 영역에는 접근할 수 없지만, 스태틱과 힙 영역은 공유해서 사용하는 구조다.
- 따라서 멀티 프로세스 대비 메모리를 적게 사용할 수 있는 구조다
멀티 프로세스
스태틱 영역 |
||
스택 (stack) 영역 |
힙(Heap) 영역 |
스태틱 영역 |
||
스택 (stack) 영역 |
힙(Heap) 영역 |
- 다수의 데이터 저장영역, 즉 다수의 T메모리를 갖는 구조다.
- 각 프로세스마다 각자의 T메모리가 있고 각자 고유의 공간이므로 서로 참조할수 없다
- 하나의 프로레스가 다른 프로세스의 T메모리 영역을 절대 침범할 수없는 메모리 안전구조이지만, 메모리 사용량은 그만큼 크다.
-> 서블릿은 요청당 프로세스가 아닌 요청당 스레드를 생성한다. = 효율적이므로
멀티 스레드와 전역변수
- 쓰기 가능한 전역변수를 사용하게 되면 스레드 안전성이 깨진다 = thread unsafe
- lock을 거는 방법이 있지만, 그 순간 스레드의 장점을 버린 것과 같다.
Field = 필드 = 속성 = 프로퍼티 = property
Function = 함수 = 메서드 = Method = 기능 = 행위
객체 지향이 힙 메모리 영역을 사용하는 방식은 기존의 절차적/구조적 언어와 차이가 있다.
- 스태틱 : 클래스들의 놀이터
- 스택 : 메서드들의 놀이터
- 힙 : 객체들의 놀이터
[참고]
스프링 입문을 위한 자바 객체 지향의 원리와 이해
'JAVA > 객체지향의 원리' 카테고리의 다른 글
[객체지향의 원리와 이해 4] 자바가 확장한 객체 지향 (0) | 2023.06.27 |
---|---|
[객체지향의 원리와 이해 3] 자바와 객체 지향 (0) | 2023.06.26 |
[객체지향의 원리와 이해 1] 사람을 사랑한 기술 (0) | 2023.06.26 |
[OOP] interface / 인터페이스 (0) | 2022.09.07 |
[OOP] abstract / 추상화 (0) | 2022.09.05 |