프로세스(Process)

운영체제로부터 자원을 할당받는 작업의 단위

사용자가 어플리케이션을 실행하면, 운영체제로부터 실행에 필요한 메모리를 할당받아 어플리케이션의 코드를 실행하는데 이것을 프로세스라고 부른다.

 

ex) Chrome 브라우저 2개 실행 = 두 개의 Chrome 프로세스가 생성 되었다.

 

자바에서 프로세스는 자바 가상 머신(JVM)이 운영체제에서 프로그램을 실행할때 생성된다. 프로세스는 독립된 실행 환경을 가지며, 다음과 같은 특징을 가진다.

  1. 독립된 주소 공간 : 프로세스는 자신의 메모리 공간을 독립적으로 가지고 있다. 다른 프로세스와 메모리 공간을 공유하지 않기 때문에 하나의 프로세스에서 발생한 오류가 다른 프로세스에 영향을 미치지 않는다.
  2. 자원 할당 : 프로세스는 CPU 시간, 메모리, 파일 핸들 등의 자원을 할당받는다.
  3. 프로세스 간 통신 : 서로 다른 프로세스는 기본적으로 독립적이기 때문에, 프로레스 간의 데이터 교환은 인터프로세스 커뮤니케이션(IPC) 기법을 통해 이루어져야 한다. IPC 방법으로는 소켓, 파일, 공유 메모리, 메시지 큐 등이 있다.

자바에서 새로운 프로세스를 생성하려면 

  1. Runtime.getRuntime().exec() 메서드를 사용하거나
  2. ProcessBuilder 클래스를 사용할 수 있습니다.

 

Runtime 클래스의 exec 메서드를  사용

import java.io.*;

public class ProcessExample {
    public static void main(String[] args) {
        try {
            // 새로운 프로세스를 생성하여 명령어 실행
            Process process = Runtime.getRuntime().exec("notepad.exe");

            // 프로세스의 출력 스트림 읽기 (예시에서는 필요 없지만 다른 명령어 실행 시 유용할 수 있음)
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 프로세스 종료 대기
            int exitCode = process.waitFor();
            System.out.println("Process exited with code: " + exitCode);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

 

ProcessBuilder 클래스를 사용하는 예시

mport java.io.*;

public class ProcessBuilderExample {
    public static void main(String[] args) {
        // ProcessBuilder 객체 생성
        ProcessBuilder processBuilder = new ProcessBuilder("ping", "-c", "4", "google.com");

        // 프로세스 출력과 오류를 동일한 스트림으로 병합
        processBuilder.redirectErrorStream(true);

        try {
            // 새로운 프로세스 시작
            Process process = processBuilder.start();

            // 프로세스의 출력 스트림 읽기
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 프로세스 종료 대기
            int exitCode = process.waitFor();
            System.out.println("Process exited with code: " + exitCode);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

 

프로세스 간 통신 예시

자바에서는 소켓을 사용하여 프로세스 간 통신을 구현할 수 있다. 간단한 서버-클라이언트 예제를 통해 프로세스 간 통신을 알아보자

 

서버 예제

import java.io.*;
import java.net.*;

public class Server {
    public static void main(String[] args) {
        // 서버 소켓을 생성하여 포트 5000에서 클라이언트 연결 대기
        try (ServerSocket serverSocket = new ServerSocket(5000)) {
            System.out.println("Server started. Waiting for a client...");

            // 클라이언트 연결 수락
            try (Socket clientSocket = serverSocket.accept();
                 // 클라이언트와 통신을 위한 출력 스트림 생성
                 PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
                 // 클라이언트와 통신을 위한 입력 스트림 생성
                 BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))) {

                System.out.println("Client connected.");

                String inputLine;
                // 클라이언트로부터 데이터 수신 및 처리
                while ((inputLine = in.readLine()) != null) {
                    System.out.println("Received: " + inputLine);
                    // 클라이언트로 데이터 전송
                    out.println("Echo: " + inputLine);
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

클라이언트 예제

import java.io.*;
import java.net.*;

public class Client {
    public static void main(String[] args) {
        // 서버에 연결
        try (Socket socket = new Socket("localhost", 5000);
             // 서버로 데이터 전송을 위한 출력 스트림 생성
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             // 서버로부터 데이터 수신을 위한 입력 스트림 생성
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             // 사용자 입력을 위한 표준 입력 스트림 생성
             BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {

            String userInput;
            // 사용자 입력을 읽어 서버로 전송하고, 서버의 응답을 출력
            while ((userInput = stdIn.readLine()) != null) {
                out.println(userInput);
                System.out.println("Server response: " + in.readLine());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

이 예시는 서버가 클라이언트의 메시지를 받아 그대로 돌려주는 간단한 코드이다. 

'Back-End > Java' 카테고리의 다른 글

try-catch  (0) 2024.07.06
스레드  (1) 2024.07.05
Java HTTP 통신  (4) 2024.06.12
Exception과 Transaction  (1) 2024.02.05
String, StringBuilder, StringBuffer 의 차이점  (1) 2023.10.26

주기억장치의 종류에는 크게 RAM과 ROM 두 가지가 있고, 메모리라는 용어는 그 중 RAM을 지칭하는 경우가 많다.

 

RAM의 특징

RAM은 실행할 대상을 저장한다. 하지만 전원이 꺼지게 되면 데이터가 날아가기 때문에 보조기억장치라는 전원이 꺼져도 데이터를 저장할 수 있는 장치가 필요하다.

RAM

 

RAM(2)

 

RAM이 크면 뭐가 좋을까? RAM의 용량을 컴퓨터 성능에 어떤 영향을 미칠까?

 

RAM의 용량과 성능

RAM의 용량이 작을때

 

위 그림과 같이 RAM이 작아서 프로그램 3개중 하나만 저장가능하다고 가정해보자 CPU가 한번에 여러가지 연산을 할 수 없게된다.

 

반대로 RAM이 크면 어떻게 될까?

RAM의 용량이 클때

 

바로바로 RAM에서 데이터를 사용할 수 있다. 많은 프로그램을 동시에 실행하는 데에 유리하다.

 

RAM의 종류

1. DRAM(Dynamic RAM)

  • Dynamic = "동적의"
  • 저장된 데이터가 동적으로 사라지는 RAM이다.
  • 데이터 소멸을 막기 위해 주기적으로 재활성화 해야 한다. 
  • 일반적으로 메모리로 사용되는 RAM, 상대적으로 소비전력이 낮고 저렴하고 집적도가 높아 대용량으로 설계하기 용이하다.

2. SRAM(Static RAM)

  • Static = "정적의"
  • 저장된 데이터가 정적인 (사라지지 않는) RAM (전원이 연결되어 있을때만)
  • DRAM 보다 일반적으로 더 빠름
  • 일반적으로 캐시 메모리에서 사용되는 RAM, 상대적으로 소비전력이 높고 가격이 높고 집적도가 낮아 대용량으로 설계할 필요는 없으나 빨라야 하는 장치에 사용한다.

DRAM vs SRAM

 

3. SDRAM(Synchronous DRAM)

  • 특별한 (발전된 형태의) DRAM
  • 클럭 신호와 동기화된 DRAM

4. DDR SDRAM(Double Data Rate SDRAM)

  • 특별한 (발전된 형태의) SDRAM
  • 최근 가장 대중적으로 사용하는 RAM
  • 대역폭을 넓혀 속도를 빠르게 만든 SDRAM (주고받는 데이터 양을 많게 한 RAM)
  • 대역폭은 데이터를 주고받는 길의 너비

SDR SDRAM vs DDR SDRAM

 

SDR SDRAM vs DDR2 SDRAM

 

 

'컴퓨터구조와 운영체제' 카테고리의 다른 글

캐시 메모리  (0) 2024.07.12
메모리의 주소 공간  (0) 2024.07.07
명령어 집합 구조  (2) 2024.07.02
명령어 병렬 처리 기법(CPU)  (3) 2024.07.01
빠른 CPU를 위한 설계 기법  (0) 2024.06.28

명령어는 어떻게 생겨야 명령어 파이프라이닝에 유리할까?

명령어 집합 

CPU는 명령어를 실행한다. 근데 모든 CPU가 똑같이 생긴 명령어를 처리할까?

명령어의 세세한 생김새, 연산, 주소 지정 방식 등은 CPU마다 다르다.

 

명령어 집합 (구조) : CPU가 이해할 수 있는 명령어들의 모음 (=CPU의 언어)

인텔의 CPU

 

CPU는 명령어 집합에 속해있는 명령어만 이해하고 처리할 수 있다.

명령어 처리

 

위 그림처럼 같은 소스코드를 컴파일해도 CPU에 따라 저급언어가 다르게 생성되는 것을 볼 수 있다.

 

명령어가 달라지면 많은 것들이 달라진다. ex) 명령어 해석 방식, 레지스터의 종류와 개수, 파이프라이닝의 용이성...

 

ISA

 

ISA는 CPU의 언어이자 하드웨어가 소프트웨어를 어떻게 이해할지에 대한 약속이다.

 

 

명령어 집합의 두 축 : CISC & RISC

 

CISC(Complex Instruction Set Computer)

복잡한 명령어 집합을 활용하느 컴퓨터(CPU). x86, x86-64는 CISC 기반 명령어 집합 구조이다.

복잡하고 다양한 명령어를 활용하며 명령어의 크기가 다양한 가변 길이 명령어를 활용한다.

 

 

CISC

 

다양하고 강력한 명령어를 활용하기 때문에 상대적으로 적은 수의 명령어로도 프로그램을 실행할 수 있다.

 

이러한 이유로 메모리를 최대한 아끼며 개발해야 했던 시절에 인기가 높았으나 명령어 파이프라이닝이 불리하다는 치명적인 단점이 존재하여 지금은 인기가 시들해졌다. 

 

명령어가 워낙 복잡하고 다양한 기능을 제공하는 탓에 명령어의 크기와 실행되기까지의 시간이 일정하지 않고 복잡한 명령어 때문에 명령어 하나를 실행하는 데에 여러 클럭 주기가 필요하다.

 

게다가, 대다수의 복잡한 명령어는 사용 빈도가 낮다.

 

 

 

RISC(Reduced Instruction Set Computer)

명령어의 종류가 적고, 짧고 규격화된 명령어를 사용한다.

RISC

 

짧고 규격화된 명령어를 활용하기 때문에 파이프라이닝에 유리하다. 메모리 접근 최소화(load, store), 레지스터를 많이 사용한다.

 

 

정리

 

'컴퓨터구조와 운영체제' 카테고리의 다른 글

메모리의 주소 공간  (0) 2024.07.07
RAM의 특성과 종류  (1) 2024.07.03
명령어 병렬 처리 기법(CPU)  (3) 2024.07.01
빠른 CPU를 위한 설계 기법  (0) 2024.06.28
명령어 사이클과 인터럽트  (1) 2024.06.27

+ Recent posts