📌프로그램이 메모리 사용하는 방식
데이터 저장 영역 = 스태틱 영역 + 스택 영역 + 힙 영역
💡main 메소드 실행될 때 데이터 저장 영역
- JRE는 프로그램안에 main() 메소드가 있나 확인한다.
- main() 메소드 존재가 확인되면 JVM에 전원을 넣어 부팅한다.
- JVM은 목적 파일을 받아 목적 파일을 실행한다.
- JVM은 java.lang 패키지를 데이터 영역의 스태틱 영역에 가져다 놓는다.
- 개발자가 작성한 모든 클래스와 import 패키지를 스태틱 영역에 가져다 놓는다.
- main() 메소드 구동 위해 스택 프레임이 스택 영역에 할당된다.
- 정확히 말하면 클래스 정의를 시작하는 중괄호를 제외한 모든 여는 중괄호를 만날 때마다 스택 프레임이 하나씩 스택 영역에 할당된다.
- 메소드의 인자를 저장할 변수 공간을 스택 프레임의 맨 밑에 할당한다.
- 메소드 인자뿐만 아니라 새로 지역 변수를 할당하면 스택 프레임 밑에서부터 위로 변수 공간을 마련한다.
- 메소드의 중괄호가 아닌 if문 같은 블록의 중괄호일 경우 해당 프레임 내에 블록의 스택 프레임이 생성된다.
- 닫는 중괄호를 만나면 해당 스택 프레임이 소멸된다.
- main() 메소드의 닫는 중괄호를 만나면 스택 프레임을 소멸한다. 이때, T 메모리 소멸, JVM 기동 중지, JRE가 사용했던 시스템 자원을 OS에 반납한다.
💡변수에 따른 저장 영역 위치
변수도 메모리에 있다 했는데 데이터 저장 영역 중 어디에 위치해 있어야 할까?
답은 세 군데 모두이다. 스태틱 영역, 스택 영역, 힙 영역에 모두 위치할 수 있는데 각기 다른 용도를 갖는다.
- 클래스 멤버 변수
스태틱(static) 영역에 위치한다. 스태틱 영역에 한번 자리 잡으면 JVM이 종료될 때까지 할당되어 있다. - 지역 변수
스택(Stack) 영역에 위치한다. [main 메소드 실행될 때 데이터 저장 영역]에서도 설명했지만, 스택 프레임 내 밑에서부터 공간을 마련하여 위치한다. 따라서 스택 프레임이 사라지면 함께 사라진다. - 객체 멤버 변수
힙(Heap)에 위치한다. 객체 멤버 변수는 객체와 함께 가비지 컬렉터(Garbage Collector)라고 하는 힙 메모리 회수기에 의해 소멸한다.
💡전역 변수와 메모리
static int count;
위와 같이 static 키워드가 붙어있는 변수가 선언되어 있을 때, count 변수는 데이터 저장 영역 중 스태틱 영역에 변수 공간이 할당 된다. main() 메소드도 스태틱 영역에 할당되는데 main() 메소드 역시 앞에 static 키워드가 붙어있다.
전역 변수는 코드 어느 곳에서나 접근할 수 있다고 해서 전역 변수라고 불리며, 여러 메소드들이 공유해서 공유 변수라고도 불린다. 공부하다보면 전역 변수는 지양하라는 말을 들은 적이 있을 것이다. 이유는 무엇일까? 바로 프로젝트 규모가 커지면서 전역 변수 관리가 힘들어지기 때문이다. 모든 곳에서 전역 변수에 접근할 수 있기 때문에 어디서 전역 변수를 건드렸는지 추적하기가 힘들다. 전역 변수는 읽기 전용으로 값을 공유해서 전역 상수로 쓰일 때만 사용하는 것이 좋다. 예를 들어 PI = 3.14 같은 경우 전역 상수로 선언하는 것이 좋다.
멀티 스레드 / 멀티 프로세스의 이해
멀티 스레드를 사용하다보면 전역 변수를 사용하는 것이 문제를 일으킨다. 차근차근 설명해보도록 하겠다.
데이터 저장 관점으로 본다면 멀티 스레드는 스택 영역을 스레드 개수만큼 분할해서 쓰는 것이다.
멀티 프로세스는 다수의 데이터 저장 영역을 갖는 구조이다.
멀티 프로세스는 각 프로세스마다 각자의 데이터 저장 영역을 갖기 때문에 서로 참조할 수 없다. 때문에 다른 프로세스의 데이터 저장 영역을 침범할 수 없는 메모리 안전한 구조이지만 메모리 사용량을 그만큼 크다.
반면 멀티 스레드는 하나의 데이터 저장 영역을 사용하고 스택 영역만 분할해서 사용하는 구조이기 때문에 하나의 스레드에서 다른 스레드의 스택 영역에는 접근할 수 없지만 스태틱 영역이나 힙 영역은 공유해서 사용하여 멀티 프로세스 대비 메모리를 적게(효율적으로) 사용한다.
이제 멀티 스레드에서 전역 변수를 사용할 경우를 생각해보자. 전역 변수는 스태틱 영역에 할당되어 모든 스레드가 공유할 수 있기 때문에 전역변수에 대해 스레드 안전성이 깨진다. 물론 이를 보완하는 방법으로 락(lock)을 거는 방법이 있지만 락(lock)을 거는 것은 멀티 스레드의 장점을 버린 것과 같기 때문에 전역 변수를 지양하는 것이 최선의 방법이다.
💡클래스에서 인스턴스가 생성되었을 때
public class Human{
public String name;
public void speak() {
System.out.println("난 " + name + "이야");
}
}
public class Test{
public static void main(String[] args){
Human IU = new Human();
IU.name = "이지은";
IU.speak();
}
}
위 코드를 실행할 때 데이터 저장 영역에 대해 설명하도록 하겠다.
처음 java.lang 패키지와 모든 클래스(Human, Test)가 스태틱 영역에 배치될 것이다.Human 클래스가 스태틱 영역에 배치될 때 name, age, gender의 변수 저장 공간이 할당되지 않고 그저 이름만 존재한다. 객체가 생성돼야만 속성의 값을 저장하기 위한 메모리 공간이 할당되는데 스태틱 영역에 할당되지 않고 힙(Heap) 영역에 할당된다.
// Human 객체애 대한 참조 변수 IU를 만든다.
// Human IU에 의해 힙에 생성된 인스턴스를 참조할 수 있는 객체 참조 변수 IU가
// 스택 영역 안에 있는 main() 메소드 스택 프레임 안에 생성된다.
Human IU
// Human 클래스의 인스턴스를 하나 만들어 힙(Heap)에 배치한다.
// 이때 인스턴스의 시작 주소가 할당되고
// 이 주소 번지가 IU 객체 참조 변수에 할당되어 해당 인스턴스를 가리키게 된다.
new Human()
// Human 객체에 대한 주소를 참조 변수 IU에 할당한다.
Human IU = new Human()
💡상속에서 데이터 저장 영역
public class Singer extends Human{
public String gender;
public void showGender(){
System.out.println("내 성별은 " + gender);
}
}
위와 같이 Human을 상속받은 Singer 클래스를 정의하자.
public Class Test{
public static void main(String[] args){
Singer IU = new Singer();
IU.name="이지은";
IU.gender="FEMAIL";
IU.speak();
IU.showGender();
}
}
Singer IU = new Singer(); 를 실행했을 때 Singer 클래스의 인스턴스만 힙 영역에 생기는 것이 아니라 상위 클래스인 Human 클래스의 인스턴스도 함께 힙 영역에 생긴다. 즉, 하위 클래스의 인스턴스가 생성될 때 상위 클래스의 인스턴스도 함께 생성된다. 이는 Java의 구동 원리를 이해하는데 큰 도움이 되므로 꼭 기억하길 바란다. 사실 Human 인스턴스 외에도 하나의 객체가 더 생성되는데 바로 Object 클래스의 인스턴스다. Object 클래스는 모든 클래스의 최상의 클래스이므로 모든 클래스들이 이를 상속받고 있다.
IU라는 객체 참조 변수는 Singer 인스턴스를 가리키고 있다.
public class Test{
public static void main(String[] args){
Human IU = new Singer();
IU.name="이지은";
IU.speak();
}
}
IU라는 객체 참조 변수는 Singer() 인스턴스가 아닌 Human 인스턴스를 가리키고 있다. 때문에 사실 인스턴스는 Singer 인스턴스면서 Human 인스턴스를 가리키고 있기 때문에 gender 속성과 showGender() 메소드를 사용할 수 없다.
'Java' 카테고리의 다른 글
[Java] SOLID: 객체 지향 설계 5원칙 (0) | 2022.07.23 |
---|---|
[Java] 객체 지향(OOP)의 4대 특성 (0) | 2022.07.22 |
[이클립스] Github(깃허브)에서 source(소스) clone(가져오기) (0) | 2022.07.08 |
[Java] JavaFX 이클립스에 세팅 (0) | 2022.06.07 |
[Java] JavaFX 개요 (0) | 2022.06.07 |