Java/스프링 입문을 위한 자바 객체 지향의 원리와 이해

Ch 02. Java와 절차적/구조적 프로그래밍

계란💕 2023. 11. 26. 00:49

 

Java 로 작성된 프로그램을 실행하기 위한 과정에 대해 알아보려고한다. 

 


JDK, JRE, JVM 의 역할

  • Java 로 작성된 프로그램을 실행하기 위해서는 JVM(Java Virtual Machine, 자바 가상 머신)이 필요하다. 
  • JVM으로 Java 코드를 실행하는 것은 컴퓨터가 어떤 프로그램을 실행하는 것과 비슷하다. 
    • ex) 어떤 소프트웨어 개발자가 개발 도구를 이용해서 개발하고 OS를 통해서 물리적 컴퓨터인 하드웨어 상에서 구동한다. 
  • JDK(Java Development Kit, 자바 개발 도구): JVM용 소프트웨어 개발 도구이다. 컴파일러인 javac.exe를 포함한다. 
  • JRE(Java Runtime Enviornment): JVM용 운영체제로서Java.exe(자바 프로그램 실행기)를 포함한다. 
  • JVM(Java Virtual Machine): 가상 컴퓨터로서 하드웨어 역할

 


T 메모리 구조

  • T 메모리란? 
    • 이 책(스프링 입문을 위한 자바 객체 지향의 원리와 이해)에서는 저자가 설명상 편의를 위해서 데이터가 저장되는 영역을  "T 메모리" 라고 지칭했다. 
    • T 메모리 static / stack / heap 영역으로 구성된다. (실제 코드는 code 영역에 존재한다. )
  • static (스태틱) 영역: 클래스, 전역 변수 존재, JVM이 종료될 때까지 데이터가 고정된 상태로 존재한다. 
  • stack (메서드) 영역: 메서드, 지역 변수 존재, 중괄호가 열릴 때마다 새로운 스택 프레임이 생성된다. 
  • heap (힙) 영역: 객체, 객체 멤버 변수 존재

 

 

전역 변수(공유 변수)

  • static  (스태틱) 영역에 존재하는 전역 변수는 스택 프레임과 종속적이다. 
  • 어느 코드에서나 전역 변수에 접근 가능하다. 
  • ※ 전역 변수를 쓰지 말아야되는 이유
    • 큰 프로젝트의 경우, 여러 메서드에서 전역변수의 값을 변경하면 T 메모리로 추적하지 않는 이상 전역 변수에 저장된 값을 파악하기 쉽지 않기 때문이다.
    • 쓰기 가능한 전역 변수를 사용하면 스레드 안전성이 깨진다. 이는 lock(락)으로 보완 가능하지만 lock(락)을 쓸 경우에는 멀티 스레드의 장점이 사라진다. 

 


Java  main() 메서드 구동 과정

T 메모리 구조 - 위: 스태틱 영역, 하단 왼쪽: 스택 영역, 하단 오른쪽: 힙 영역

  • 먼저, 운영체제 역할을 하는 JRE는 main() 메서드의 존재를 확인한다. 
  • 프로그램 실행하기 위한 사전 준비가 시작
  • 하드웨어 역할을 하는 JVM에 전원을 넣어 부팅한다. 
  • 부팅된 JVM은 목적 파일(확장자가 '.class' 인 바이트 코드 파일)을 받아서 실행한다. 
  • JVM은 전처리 시작
    1. java.lang 패키지를 static 영역에 갖다놓는다. 
    2. import 된 패키지를  static 영역에 갖다놓는다. 
    3. 프로그램의 모든 클래스를 static 영역에 갖다놓는다.
  • stack 영역에 스택 프레임이 할당된다. (클래스를 정의할 때 쓰는 중괄호를 제외하고) 중괄호 '{' 를 열 때마다 스택 프레임이 생성된다. 닫으면 소멸.
  • 위 사진과 같이 T메모리를 구성하고 나서야 main() 메서드 안의 명령문을 실행하게 된다. 
  • main() 의 닫는 중괄호와 함께 스택 프레임이 사라지며 프로그램이 종료된다.
  • main() 메서드 실행이 끝난 다음에 JRE는 JVM의 전원을 끄고 JRE 자체도 OS 상의 메모리에서 사라진다. 

 


T 메모리와 멀티 스레드 / 멀티 프로세스

  • 멀티 스레드와 멀티 프로세스는 메모리를 사용하는 방식이 다르다. 

 

 

멀티 스레드

  • 하나의 T 메모리 안에 stack 영역을 스레드 개수만큼 분할해서 쓰는 구조이다.
  • 메모리 사용량이 적다. 

 

 

  Ex) 멀티 스레드 

<hide/>
public class Start6 extends Thread{
    static  int share;
    public static void main(String[] args) {
        Start6 t1 = new Start6();
        Start6 t2 = new Start6();
        t1.start();
        t2.start();
    }
    @Override
    public void run() {
        for(int count = 0; count < 10; ++count){
            System.out.println(share++);
            try{
                sleep(10000);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
  • 동시에 실행중인 두 개의 스레드가 특정 static 변수에 동시에 접근하는 경우, 같은 값이 출력된다.

  Note) 실행 결과

  • 0 1 2 2 3 3 4 4 5 5 6 7 8 9 11 10 12 12 13 14

 

 

멀티 프로세스

  • 여러 개의 T메모리를 갖는 구조이다. 
  • 메모리 사용량이 크다. 
  • 각 프로세스는 다른 프로세스의 데이터에 접근 불가능

 


Note

  • CallByValue(값에 의한 전달): 어떤 메서드의 인자에 변수를 넣어서 전달할 때, 변수 자체가 이동하는 게 아니라 변수의 값이 복사된 형태로 전달된다. 이런 전달 방식을  'CallByValue ' 라고 한다. 

 


찾아보기

  • 쓰기 가능한 전역변수에 대해 lock을 쓰면 멀티스레드의 장점이 사라지는 이유

 

출처 - 「 스프링 입문을 위한 자바 객체 지향의 원리와 이해 - 김종민 」