728x90
반응형

컴퓨터 성능에서 제일 많은 부분을 차지하는 것은 응답시간과 처리량이다. (response time, throughput)

그냥 모든 기계를 생각해도 비슷할 것이다. 기계가 일을 하는데 걸리는 시간. 즉, 일 하나를 하는데 얼마나 많은 시간이 걸리느냐랑 주어진 시간동안 얼마나 많은 일을 하느냐. 

이 2가지가 컴퓨터의 성능을 결정한다. 

 

성능(performance)는 응답시간(response time)이 짧을 수록 좋을 것이다. 즉 서로 반비례 관게인 것이다. 

예를 들어서, 동일한 일을 수행하는데 A 컴퓨터는 10초가 걸리고, B 컴퓨터는 15초가 걸린다고 가정하자. 

그럼 A컴퓨터가 B컴퓨터보다 성능이 1.5배 좋다라고 생각할 수 있다. 

결국 CPU performance를 측정한다는 것은 CPU time을 기준으로 performance를 측정한다.

 

CPU Time은 어떻게 구할까?

CPU Time = CPU Clock Cycles X Clock Cycle Time = CPU Clock Cycles / Clock Rate

해당 식을 어떤 의미인지 확인해보자.

한 Clock당 시간을 Clock Cycle Time이라고 하고, 그럼 총 Cycle을 구하면 CPU Time을 구할 수 있으니까 CPU Clock Cycles(사이클 수)를 곱해주면 전체 시간이 나오게 된다. 

Clock Cycle Time, 즉 한 Clock당 시간은 Clock Rate의 역수이다. 

 

그럼 위의 식에서 CPU Time이 나오는데, CPU Time은 Performance와 반비례 관계라고 했다. 그럼 Performance를 향상시킬 수 있는 방법은 무엇일까? (CPU Time을 작게 만들 수 있는 방법)

- clcok cycles의 수를 줄인다.

- clock rate를 늘린다. = cycle time을 줄인다.

- 그런데 늘 위의 방법을 한다고 다 빨라지는건 아니다. Clock Rate를 증가시키다보면 CPU Clock Cycles가 증가할 수도 있고 이런 문제가 생긴다. (서로 trade off가 있다)

 

조금 더 자세히 Clock Cycles를 살펴보자. 

Clock Cycles = Instruction Count X Cycles per Instruction(CPI)
즉, Clock Cycle은 명령어의 갯수 X 명령어당 필요한 Cycle의 수.

여기서 instruction 1개당 필요한 cycle 수가 CPI이다. 그럼 다음과 같은 식이 나온다. 

 

Instruction Count는 알고리즘을 어떻게 짜느냐, 어떤 ISA를 갖고 있느냐, compiler에 따라 개수가 바뀐다.

 

하나의 cycle당 하나의 명령어를 처리한다고 생각할 수 있는데, 그게 아니라 하나의 명령어도 여러 cycle로 걸린다.

그래서 Instruction에 따라서 몇 cycle이 필요한지, 명령어에 따라 다르다. (CPI가 다 다르다)

 

Average CPI(Average Cycles Per Instruction)는 CPU 하드웨어에 의해 결정되고 다른 instruction을 가지면 다른 CPI를 가지게 된다. 

 

이제는 CPI에 대해서 더 자세히 알아보겠다. 

Clock Cycles은 총 사이클 도는데 걸리는 시간이라고 했다. 그리고 명령어마다 필요한 cycle이 다르다.

따라서, CPI에 Instruction개수를 곱한 값들의 합이 Clock Cycles이 된다.

CPI는 명령어 타입마다 다르기 때문에,CPI와 Instruction count는 다 다르기 때문에 저렇게 다 곱해서 더해야지 정확한 Clock Cycles의 값이 나오게 되는 것이다.

 

그럼 평균값도 똑같다.

CPI의 평균 값은 Clock Cycles을 총 Instruction Count로 나누어주면 된다(그냥 위의 계산의 반대이다.)

여기서 Instruction Count / 총 Instruction Count 를 Relative Frequency라고 한다. 그럼 해당 명령어가 총 명령어에 사용된 비율을 알 수 있다. 

728x90
반응형

'CS > 컴퓨터 구조' 카테고리의 다른 글

암달의 법칙 (Amdahl's law)  (0) 2023.03.20
컴퓨터 구조와 언어  (2) 2023.03.05
컴퓨터 아키텍처를 발전시킨 7가지 아이디어  (0) 2023.03.05
728x90
반응형

개념적인 이야기보다 제가 놓치기 쉬운 것들을 기록하였습니다.

상속

  • java의 모든 클래스는 Object 클래스를 상속받는다.
  • Object 클래스의 메서드 오버라이딩
    • toString()
  • super : 상위 클래스의 값을 가져올 수 있도록 도와준다.
  • 다중 상속 : C++은 다중 상속이 되지만, 자바에서는 허용하지 않는다. (다중 상속을 하면 프로그램이 복잡해져서 그런가..?)
    • 그래서 차례대로 하나씩 상속시키면 된다. (상속 계층)
    • 하위 클래스 변수를 담을 수 있는 상위 클래스 참조 변수를 만들 수 있다! → 다형성 핵심 ( 부모는 자식을 언제나 담을 수 있다 )
  • instanceof : 현재 객체가 상위 클래스의 인스턴스인지 확인할 수 있다. 맞으면 true를 리턴해줌. (하위 클래스) instanceof (상위 클래스) → true

추상화

  • 추상 메소드를 정의하려면, 추상 클래스를 정의해야 한다.
  • 하위 클래스들이 추상 메소드의 사용방법을 적용한다. → 추상클래스를 상속해서 구상 클래스 만듬.
  • 추상클래스는 새로운 인스턴스를 만들 수 없다.
  • 추상클래스 안에는 비추상적 메소드도 가질 수 있다.

다형성

인터페이스

  • 하나에 여러 개의 적용법이 있을 수 있다. —> 다형성의 핵심 개념. 같은 것에 여러 가지 구현을 부여할 수 있다.
  • 인터페이스는 공통적인 시행 가능 행동들을 대표하는 것이다. 공통 행동을 클래스에게 전달하는 역할.
  • 특정 클래스가 확실히 구현할 메소드들이 무엇인지, 시스템 안의 모든 다른 클래스들은 그 특정 클래스가 모든 메소드들을 담을 것을 기대한다.
  • 인터페이스는 또다른 인터페이스를 상속할 수 있다.
  • 인터페이스 안에서는 변수가 아니라 상수만 선언할 수 있다.

인터페이스 vs 추상화

  • 별다른 관계는 없다. 문법이 비슷해보일 뿐이다.
  • 인터페이스는 언제 사용하는 것일까? : 두 시스템 사이에 소통하길 원하거나 소통 방식을 정하고 싶을때. → implements
  • 추상클래스는 높은 단계의 구조를 제공하고 싶어 할 때 사용. 구현의 세세한 부분들은 하위 클래스에 맡기고 싶을 때. → 상속 extends
  • 인터페이스 안에는 어떤 메소드도 private으로 선언할 수 없다. 모든 것은 public
  • 인터페이스 안에는 변수들을 넣을 수 없다. 모든 것은 상수.
  • 한 클래스는 여러 인터페이스들은 구현할 수 있지만, 여러 추상적 클래스들을 상속할 수는 없다.

다형성

  • 다형성은 인터페이스에 적용되는 만큼 상속 개념에도 적용된다.
728x90
반응형

'백엔드 > Java' 카테고리의 다른 글

[Java] Java Collection 한번에 정리하기  (0) 2023.04.03
[Java] 추상클래스 vs 인터페이스  (0) 2023.03.23
Array, ArrayList  (0) 2023.03.17
Java 실행 원리와 JVM  (0) 2022.11.13
static keyword 정적 키워드  (0) 2022.11.06
728x90
반응형

Array

  • 선언은 2가지 방식으로 할 수 있다.
int[] marks = {1,2,3,4,5};
int[] marks = new int[5];
  • java의 배열의 length는 속성이지, 메서드가 아니다.
marks.length
  • 배열의 요소들을 출력하고 싶다면, for문을 사용해서 인덱스마다 출력해도 되고, Arrays.toString(배열이름); 을 사용해도 된다. (배열의 콘텐츠 불러오기)
System.out.println("Arrays.toString(persons) = " + Arrays.toString(persons));
// Arrays.toString(marks) = [1, 2, 3, 4, 5]
  • 배열의 모든 값을 한번에 바꾸는 방법도 있다. Arrays.fill(배열이름, 바꾸고 싶은 값);
int[] marks2 = {100, 99, 95, 96, 100};
for (int mark : marks2) {
    System.out.println("mark = " + mark);
}

Arrays.fill(marks2, 100);
for (int mark : marks2) {
    System.out.println("mark = " + mark);
}
  • 두 배열이 같은 요소를 가지는지 확인할 수 있다. Arrays.equals(배열1, 배열2)
Arrays.equals(marks, marks2)
  • 배열 정렬 Arrays.sort(배열이름);
  • inline : 함수의 내용을 호출을 통해서 실행시키는 것이 아니라, 호출하는 코드 자체가 함수 내용의 코드가 된다.
int[] marks = {100, 90, 80, 20, 40};
Student student = new Student("김태헌", marks);
// inline
Student student = new Student("김태헌", new int[] {100, 90, 80, 20, 40});
  • 가변 변수를 인자로 입력받기 ( 배열의 크기가 다양할 때 사용하면 좋다 ) … 을 사용하면 된다. 가변 인수는 항상 메소드의 마지막에 와야 한다!
void print(int... values){
    System.out.println("Arrays.toString(values) = " + Arrays.toString(values));
}

student.print(1,2,3,4,5); // Arrays.toString(values) = [1, 2, 3, 4, 5]
student.print(1,2); // Arrays.toString(values) = [1, 2]

int sum(int... values) {
    int sum = 0;
    for (int value : values) {
        sum += value;
    }
    System.out.println("sum = " + sum);
    return sum;
}
student.sum(1,2,3,4,5,346,234,23,42,34,23,423); // sum = 1140
  • Array에 다른 요소 하나 추가하는 방법 → 배열 자체를 새로 만들어야 한다. (배열을 한 번 생성 했다면 이후에 요소의 개수를 변경할 방법은 없다)
  • Array에 요소를 지우고 싶은 경우에도 새로운 배열을 만들면 된다
  • 이 과정이 귀찮으므로 ArrayList에 있는 메서드를 사용하면 된다.

ArrayList

  • ArrayList는 다음과 같이 선언한다.
    add와 remove를 이용해서 추가하고 제거할 수 있다.
ArrayList arrayList = new ArrayList();
arrayList.add("Apple");
arrayList.add("Banana");
arrayList.add(1); // String과 Int가 섞여서 들어갈 수 있다. 그치만 같은 자료형이 들어가는 것이 좋다.
System.out.println("arrayList = " + arrayList);
arrayList.remove("Apple");
System.out.println("arrayList = " + arrayList);
  • ArrayList에는 다양한 자료형이 들어가도 되지만 같은 자료형이 들어가는 것이 좋으므로, 미리 자료형을 선언한다. 그럼 다른 자료형이 들어가면 오류가 난다.
ArrayList<String> items = new ArrayList<>(); // 제네릭
728x90
반응형
728x90
반응형

https://www.acmicpc.net/problem/2636

 

2636번: 치즈

첫째 줄에는 사각형 모양 판의 세로와 가로의 길이가 양의 정수로 주어진다. 세로와 가로의 길이는 최대 100이다. 판의 각 가로줄의 모양이 윗 줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진

www.acmicpc.net

[문제 이해와 내가 푼 방법]

처음에 문제를 읽고 나서는 간단한 탐색 문제라고 생각하였다.

일단 치즈인지 아닌지 판단하여, 제일 겉에 있는 치즈들을 모두 없애주고 사이클을 도는 횟수를 저장하고, 남은 치즈도 따로 저장하는 이 과정을 반복하면 된다고 생각하였다.

 

이렇게 단순한게 생각하고 접근하였는데 고려해야할 사항이 하나 더 있었다.

제일 겉에 있는 것을 어떻게 판단할 것인가의 문제였는데, 처음에는 0이 있는 칸이 상하좌우에 하나라고 있으면 겉에 있는 치즈라고 생각하였는데, 그것만으로는 판단이 불가능 했다.

해당 그림에서 파란색은 모두 겉에 있는 치즈가 맞지만 빨간색까지 포함시킨다는 점이 문제였다. 

그래서 탐색을 할 때 수정이 필요했다. 

 

나는 BFS를 사용하였는데, 일단 (0,0)을 BFS의 deque로 받았다. 그리고 방문하였는지 확인해야하기 때문에 visited 배열도 따로 만들어주었다. 

 

그리고, q에는 아직 방문하지 않았고, 그래프에서 0인 점을 q에 append 한다. 

만약 아직 방문하지 않았고, 그래프에서 1인점은 치즈인 점이다. 해당 좌표는 겉에 있는 치즈이기 때문에 0으로 바꿔주고 갯수를 체크해준다. 그치만 이 점은 q에 넣어주지 않는다. 해당 점을 넣어주게 되면 겉에 있는 치즈 이외에 안쪽에 있는 치즈까지 탐색이 되기 때문이다.

즉, 이렇게 되면 겉에 있는 치즈들과 외부의 0인 점들만 다 탐색을 하게 된다. 위에 있는 빨간색 점들과 빨간색 점들과 파란색 점들로 둘러싸인 0인 점들은 탐색을 하지 못하게 된다. (겉에서 치즈를 탐지하면 q에는 더이상 넣지 않기 때문이다.)

 

이 반복을 q가 없어질 때까지 하면, 이게 한 사이클이다. 나는 해당 사이클이 끝나면 남아있는 치즈들을 배열에 넣어주었다. 이 부분은 출력을 위해서 left_cheese에 넣어서 마지막에 정답을 출력해주었다. 

(물론 cycle이 한번밖에 없을때 조심해줘야 한다.)

 

[코드]

from collections import deque

row, col = map(int, input().split())  # 세로, 가로
graph = []
for _ in range(row):
    graph.append(list(map(int, input().split())))
cnt = 0
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

def total_cheese(graph):
    cnt = 0
    for i in range(row):
        for j in range(col):
            if graph[i][j] == 1:
                cnt += 1
    return cnt

def isCheese(a, b):  # 해당 칸이 제일 겉의 치즈인지 파악
    q = deque()
    q.append([a, b])
    visited = [[False] * col for _ in range(row)]
    cnt = 0
    while q:
        x, y = q.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0 <= nx < row and 0 <= ny < col:
                if not visited[nx][ny]:
                    if graph[nx][ny] == 0:
                        q.append([nx, ny])
                        visited[nx][ny] = True
                    elif graph[nx][ny] == 1:
                        visited[nx][ny] = True
                        graph[nx][ny] = 0
                        cnt += 1  # 겉의 치즈 개수
    return cnt

time = 0
left_cheese = []
left_cheese.append(total_cheese(graph))
while True:
    cheese = total_cheese(graph)
    time += 1
    left_cheese.append(cheese - isCheese(0, 0))
    if left_cheese[-1] == 0:
        break
print(time)
print(left_cheese[-2])
728x90
반응형

'알고리즘 > 알고리즘 문제' 카테고리의 다른 글

[알고리즘] 친구비  (2) 2023.06.03
[백준] 타임머신 11657  (0) 2023.03.22
[백준 - 1062] [파이썬] 가르침  (0) 2023.01.08
[17609] [파이썬] 회문  (0) 2023.01.08
[파이썬] [백준 - 7432번] 디스크 트리  (0) 2022.11.04
728x90
반응형

대부분의 프로그램, 흔히 우리가 Application Software라고 불리는 것들은 high level language로 작성되어 있다. 

이건 우리가 보는 거의 젤 테두리 느낌이다.

 

만약 high level language로 프로그램이 짜여져 있으면 System Software인 Compiler(컴파일러)가 기계가 이해할 수 있는 machine code로 바꾸어준다. machine code는 도저히 이제 구분하기가 어려운 10101010001.. 로만 구성된 이진 코드이다.

 

그리고 System Software에는 OS도 포함된다. Operating System, OS는 우리가 사용하는 user Program과 하드웨어 사이에서 인터페이스 역할을 한다. 기본적인 input output도 처리해 주고, 메모리도 할당해주고, 프로그램 task들을 스케쥴링하고 리소스 할당도 다 OS가 해주는 역할이다. 

 

하드웨어는 Processor, memory, I/O controller를 갖는다.

 

위에 얘기했던 HLL(High Level Language)랑 Binary Machine Language는 이제 program code의 레벨로 나눌 수 있다. 

기계가 이해할 수 있는 건 Binary Machine Language이다. 우리가 그나마 잘 이해한다는 C나 java로 코드를 짜도 기계는 이해할 수 없는 애들이다. 

 

먼저, 어셈블리 언어를 알아야 한다. 어셈블리 언어는 그래도 이진코드보다는 조금 직관적이다. 이런 어셈블리 언어로 구성된 것은 one to one으로 machine code와 매칭된다. 어셈블리 언어는 명령어를 텍스트로 나타낸 것이다. 텍스트 하나하나가 기계어로 매치되어 바뀐다. 이걸 바꿔주는게 어셈블러로 보면 된다. 

 

어셈블리 언어보다 이제 우리에게 더 직관적인게 HLL이다. High Level Language는 여러 장점이 있다. 

먼저, 개발자가 사용하는 자연어와 비슷하다. 그래서 생산성도 올라가고, 프로그램 관리도 쉬워진다. 또, 프로그램이 컴퓨터와 독립적으로 되는 것이라 효과적이다. 이러한 HLL을 어셈블리언어로 바꿔주는게 컴파일러다. 

728x90
반응형
728x90
반응형

컴퓨터 구조를 발전시킨 데에는 7가지 아이디어가 있었다.

단순히 예전에 계산에만 쓰이던 컴퓨터가 지금까지 사람들이 사용할 수 있었던 7가지 아이디어에 대해 소개하겠다.

Abstraction(추상화)

먼저 컴퓨터를 추상화함으로써 컴퓨터 사용을 더 편리하게 했다. 간단하게 디자인하게 된 것이다. 그냥 단순하게 생각하면 컴퓨터를 하드웨어랑 소프트웨어로 분리한 것도 추상화의 하나라고 생각할 수 있다.

Common Case Fast (공통 부분 빠르게!)

어떤 일을 하든지 공통적인 부분을 묶으면 빨리 할 수 있다. 컴퓨터도 이러한 일환으로 CISC과 RISC라는 개념들도 나오게 된다.

Parellelism (병렬화)

병렬화를 통해서 컴퓨터의 성능을 최대화 시켰다.

Pipelining(파이프라이닝)

이건 좀 의아할 수 있는데, 파이프라이닝?은 물 배관으로 알고 있다. 대량의 명령어가 순차적으로 처리되는 것이 물이 흐르는 과정이랑 비슷하다는 생각에서 나온 개념이라고 한다.

Prediction (예측)

컴퓨터는 예측을 통해서 명령어를 실행해 성능을 향상시켰다. 물론 이것이 취약점이 되어서 나온 문제가 Melt Down이다.

인텔 프로세서에 영향을 미치는 하드웨어 취약성인 melt down은 프로세서가 추측 실행을 처리하는 방식의 결함을 이용함으로써 작동하는데, 이것이 프로그램이 다음에 실행할 명령을 예측함으로써 처리 속도를 높이는 데 사용되는 기술이다.

Hierarchy of Memories (메모리 계층 구조)

메모리를 계층적으로 사용하는 것도 컴퓨터의 성능을 향상 시킨 요소이다.

Dependability via Redundancy(이중화를 통한 신뢰성)

RAID는 "독립 디스크의 중복 어레이"를 의미한다. 여러 개의 하드 드라이브를 사용하여 성능, 안정성 또는 둘의 조합을 향상시키는 데이터 스토리지 기술이다.

RAID의 핵심 원칙 중 하나는 "중복성을 통한 신뢰성"이다 즉, 여러 개의 하드 드라이브를 사용하여 해당 드라이브 간에 데이터를 복제하여 단일 드라이브 장애 시 중복성을 제공할 수 있다. 이러한 이중화는 우리에게 데이터의 신뢰성을 줄 수 있다.

728x90
반응형

'CS > 컴퓨터 구조' 카테고리의 다른 글

암달의 법칙 (Amdahl's law)  (0) 2023.03.20
컴퓨터 성능은 어떻게 측정할까?  (0) 2023.03.20
컴퓨터 구조와 언어  (2) 2023.03.05
728x90
반응형

가상메모리라는 것은 메모리 관리 기법 중 하나로, 프로세스 전체가 메모리 내에 올라오지 않더라도 실행이 가능하도록 하는 기법이다. 

가상 메모리의 장점은 다음과 같다.

1. 사용자 프로그램이 물리 메모리의 제약에서 벗어날 수 있다

2. 각 프로그램이 더 작은 메모리를 차지하기 때문에 더 많은 프로그램을 동시에 수행이 가능하다. (물론 그냥 가능한 것처럼 보이는 것이다.)

3. 프로그램을 메모리에 올리고 swap하는데 필요한 I/O의 횟수가 줄어든다.

 

위의 해당 내용만 알아서는 가상 메모리가 어떤 건지 잘 이해가 가지 않는다. 하나하나씩 배경지식을 알아가면서 가상메모리의 개념을 알아보겠다. 

 

먼저 메모리라는 것은 컴퓨터에서 어떤 존재일까?

컴퓨터에서 컴퓨터는 CPU가 일을 한다. 여기서 일이라 함은 연산을 수행하게 된다. 

그런데 CPU가 일을 하려면 아무 정보도 없이 할 수는 없다. 1+2를 수행하더라도 1과 2를 어디서 불러와야 한다. 

CPU가 값을 참조해야 한다는 뜻이다. 여기서 값은 레지스터라는 저장 공간에 저장되어 있다. 레지스터는 자료를 보관하는 매우 빠른 기억 장소이다. 그렇지만 레지스터는 용량이 매우 작고, 휘발성이라는 특성을 가지고 있다. 

따라서, 레지스터 보다는 조금 더 느리지만, 조금 더 큰 용량인 메인 메모리(물리적 메모리라고 한다)를 두어서 해당 내용을 참조한다. 

메인메모리가 레지스터보다는 크기가 크지만, 메인메모리와 레지스터는 용량이 작고 휘발성 특성을 가진다. 그래서, 이 둘보다는 더 많은 내용을 저장하는, 또 비휘발성의 특성을 가지는 DISK memory를 사용한다. (DISK memory는 우리가 흔히 하드디스크(HDD)라고 불리는 것이다.)

 

CPU는 레지스터와 메인메모리까지의 값만 참조할 수 있다. 그래서 보조저장장치(DISK)에 있는 값을 참조하려면 OS의 도움을 받아서 입출력 작업을 실행해야 한다. 프로그램들은 보통 DISK에 저장되어 있다.

 

그럼 DISK의 프로그램은 어떤 방식으로 해서 CPU가 실행을 하는 것일까?

먼저 DISK에 프로그램은 이진(binary) 실행 파일 형식으로 존재한다. 만약에 개발자가 작성한 소스 프로그램이 있다면 컴파일러와 링커의 작업으로 실행파일이 생성된다. 

 

예를 들어서, Java로 소스코드를 작성했다고 생각해보자. 그럼 컴파일러는 소스 코드를 내 컴퓨터에서 실행할 수 있도록 바이트 코드로 바꾸어서 소스코드를 JVM에서 실행할 수 있도록 도와준다. 그리고, 링커는 컴파일러에 의해서 생성된 파일을 가져와서 실행 파일로 결합한다. 

 

 

실행 파일을 실행하면 fork 요청으로 새 프로세스를 생성하고, exec 요청으로 로더를 호출한다. 그럼 여기서 로더는 어떤 역할을 하냐면, 로더는 새로 생성된 프로세스의 주소공간을 사용하여서 지정된 실행 파일을 메모리에 올려준다. 

즉, 프로그램을 실행하면 디스크에 존재하던 실행파일이 메모리에 올라오고, 그럼 이 내용을 CPU가 참조할 수 있게 되는 것이다. CPU가 그럼 이제 실행 파일을 실행하면 0번부터해서 시작하는 프로세스마다  독자적인 주소공간을 생성하고, CPU는 이 주소를 바라보는데, 이 주소가 바로 논리 주소이다.즉, CPU는 논리주소를 바라보고 있는 것이다. CPU가 일을 하려면 논리 주소가 메모리 상에 올라와 있어야 한다.

 

그럼 논리주소는 실제 물리적 메모리의 특정 위치와 매핑 되어야 하는데, 이 매핑 작업을 주소 바인딩 이라고 한다.

바인딩을 하는 방법은 물리적 메모리 주소가 결정되는 시기에 따라서 나누어 지는데, 컴파일 타임 바인딩, 로드 타임 바인딩, 실행 시간 바인딩으로 나누어진다.

여기서 실행 시간 바인딩을 사용하면 가상 메모리를 이제 사용할 수 있게 된다. 실행 시간 바인딩을 하기 위해서는 하드웨어적인 지원이 필요한데, CPU가 주소를 참조할 때마다 주소 맵핑 테이블을 이용해서 바인딩을 점검한다.

레지스터는 현재 프로세스의 물리적 메모리의 시작 주소가 저장되어 있다. 그래서 레지스턴는 논리 주소 + 기존 레지스터 값으로 물리적 주소의 위치를 찾는다. (아까 CPU에 올라올 때, 0번부터 프로세스가 주소공간을 생성한다고 했으니까)

 

앞에서 말한대로, CPU가 프로세스를 실행하려면 메모리에 올라와 있어야 한다. 그런데 너무 많은 프로그램이 메모리에 올라오면 메모리 공간이 부족하게 된다. 그래서 메모리 공간의 확장 영역으로 스왑 영역 이라는 것을 사용한다. 

 

스왑 공간은 외부 저장장치에 존재하지만 물리메모리의 확장 느낌이다. 물리메모리에 공간이 부족하기 때문에 실행중인 프로세스의 주소공간을 일시적으로 메모리에서 디스크로 내려 놓는 것이다.

 

스왑 영역은 디스크에 존재하지만 파일시스템과는 별도로 존재한다. 파일시스템은 비휘발성이지만 스왑영역은 메모리 공간의 확장으로 사용하기 때문에 프로세스가 수행 중인 동안에만 일시적으로 저장된다. 메모리에서 스왑영역으로의 이동을 swap in, swap out 이라고 한다.

 

스왑 영역도 외부저장장치에 존재하기 때문에 OS에 의해 IO작업이 일어난다. 하지만 공간효율성보다는 시간효율성을 고려한 저장이 일어나서 일반적으로 파일시스템에 접근하는 것보다 좀 더 빠른 접근이 가능하다.

 

 

즉, 프로세스는 메모리에 올라와야하는데, 만약 현재 실행되고 있는 프로세스 말고 다른 프로세스를 실행하려고 한다면 기존 프로세스를 스왑 영역으로 내쫓고 필요한 프로세스가 물리메모리에 올라와야 한다. 이렇게 된다면 빈번하게 스왑영역과 IO가 발생될 것이다.

만약 프로세스의 크기가 물리 메모리의 크기를 벗어난다면 실행조차 불가능하게 된다. 이런 불편함 때문에 가상메모리 개념이 필요하게 되었다.

 

즉, 필요한 내용만 물리메모리 위에 올려놓고 사용하면 되지 않을까라는 생각을 사람들이 하게 된 것이다. 이렇게 가상메모리의 개념이 등장한다.

 

가상메모리는 실제의 물리메모리 기능과 개발자의 논리메모리 개념을 분리한다.

따라서 가상메모리를 사용하면 프로세서 전체의 내용을 메모리에 올릴 필요없이 필요한 부분만 메모리에 올려 실행이 가능하다.

 

그럼 필요한 부분만 어떻게 올려 줄 수 있을까?

여기서 필요한 페이지만 물리메모리에 적재하는 **요구 페이징 기법(Demand Paging)을 사용한다.

이 기법에서는 주소공간이 하나의 단위가 아니라 여러 개의 페이지로 나눠져 있다. 그 중에서 지금 당장 필요한 페이지들만 물리 메모리에 가져와 사용한다.

 

그럼 또 의문이 생긴다. 필요한 페이지가 물리 메모리에 올라와 있는지 아닌지를 어떻게 알까?

특정 페이지 메모리 존재임을 구분하기 위해 유효(valid), 무효(invalid) 비트를 사용한다.

invalid는 해당 페이지가 메모리에 없음을 의미하고 이를 페이지 폴트(Page fault)가 발생했다고 한다. 이 경우 보조저장장치에 페이지가 있다면 보조저장장치에서 해당 페이지를 가져온다.

 물리메모리에 대응되는 페이지 테이블에 valid, invalid 비트로 물리적 메모리에서 페이지의 바인딩 정보를 확인할 수 있다. 앞서서 말한 하드웨어인 MMU의 도움을 받아 실행 타임 바인딩 기법이 적용된다.

 

여기까지의 내용을 알고 나면, 가상 메모리의 장점이 어떻게 장점이 되는지 알 수 있다.

 

728x90
반응형

'CS > TIL' 카테고리의 다른 글

[DevOps] 쿠버네티스 환경구축  (0) 2023.03.29
[DevOps] 도커  (0) 2023.03.21
Transaction과 Rollback  (0) 2023.02.14
Logging을 이용한 Database의 Recovery  (0) 2023.02.09
728x90
반응형

쿠키와 세션을 사용하는 이유는 Http의 특성 때문이다.

http는 connectionless와 stateless의 특성을 가지고 있는데, connectionless는 클라이언트가 서버에 요청했을때 응답 이후 연결을 끊어버리는 속성이고, stateless는 connection이 끊어지고 나면 상태정보 유지를 하지 않는다는 속성이다.

이러한 특성을 해결하기 위해 쿠키와 세션을 사용한다.

쿠키

  • 쿠키는 클라이언트(브라우저) 로컬에 저장되는 키와 값이 들어있는 작은 데이터 파일이다.
  • http에서 정보가 필요할 때 재사용 가능하다.
  • 사용자 인증이 유효한 시간을 명시할 수 있으며, 유효 시간이 정해지면 브라우저가 종료되어도 인증이 유지된다.
  • 클라이언트에 300개까지 쿠키저장이 가능하고 하나의 도메인당 20개의 값만 가질 수 있다.
  • 하나의 쿠키값은 4KB까지 저장한다.
  • 쿠키는 사용자가 따로 요청하지 않아도 브라우저가 Request시에 Request Header를 넣어서 자동으로 서버에 전송한다.
  • 쿠키의 동작 방식
    • 클라이언트가 페이지를 요청
    • 서버에서 쿠키를 생성
    • HTTP 헤더에 쿠키를 포함시켜서 응답
    • 브라우저가 종료되어도 쿠키 만료 기간이 있다면 클라이언트에서 보관하고 있음
    • 같은 요청을 할 경우 HTTP 헤더에 쿠키를 함께 보냄
    • 서버에서 쿠키를 읽어 이전 상태 정보를 변경할 필요가 있을 때 쿠키를 업데이트 하여 변경된 쿠키를 HTTP 헤더에 포함시켜 응답
  • 쿠키 사용 예
    • 방문 사이트 로그인 시, “아이디와 비밀번호를 저장하시겠습니까?”
    • 쇼핑몰의 장바구니 기능
    • 자동로그인 시, 팝업에서 “오늘 더 이상 이 창을 보지 않음” 체크

세션

  • 세션은 웹 브라우저를 시작하여 종료할 때까지 상태를 유지시켜준다.
  • 세션도 쿠키를 기반하고 있지만, 쿠키와는 달리 사용자 정보 파일을 서버에서 관리한다
  • 서버에서는 클라이언트를 구분하기 위해 세션 ID를 부여하며 웹 브라우저가 서버에 접속하여 브라우저를 종료할 때까지 인증상태를 유지한다
  • 접속 시간에 제한을 두어 일정 시간 응답이 없다면 정보가 유지되지 않게 설정이 가능하다
  • 사용자에 대한 정보를 서버에 두기 때문에, 서버 메모리를 많이 차지하게 된다
  • 가장 큰 차이점은 저장 위치 및 서버 사용여부이다. 쿠키는 클라이언트 로컬에 저장하여 사용하지만, 세션은 서버의 자원을 활용한다.
  • 세션의 동작 방식
    • 클라이언트가 서버에 접속 시 세션 ID를 발급 받음
    • 클라이언트는 세션 ID에 대해 쿠키를 사용해서 저장하고 가지고 있음
    • 클라이언트는 서버에 요청할 때, 이 쿠키의 세션 ID를 같이 서버에 전달해서 요청한다
    • 서버는 세션 ID를 전달받아서 별다른 작업없이 세션 ID로 세션에 있는 클라이언트 정보를 가져와서 사용한다
  • 각 클라이언트에게 고유 ID를 부여한다
  • 세션 ID로 클라이언트를 구분해서 클라이언트의 요구에 맞는 서비스를 제공한다
  • 보안 면에서 쿠키보다 우수하다

보안 면에서는 세션이 쿠키보다 높지만, 서버의 자원을 활용하기 때문에 무분별하게 사용할 수는 없다.

중요한 차이점은, 라이프사이클이 세션은 웹브라우저가 종료되면 끝나지만, 쿠키는 사용기한과 데이터 파일이 있는 한 브라우저가 종료되어도 유지된다.

속도는 세션보다 쿠기가 더 빠르다.

 

[참고]

https://interconnection.tistory.com/74

 

쿠키와 세션 개념

노션 페이지(아래 내용과 동일) 개요 쿠키와 세션은 개발자 말고도 인터넷 사용자라면 누구나 많이 들어본 단어입니다. 하지만 개념에 대해서는 많은 사람들이 헷갈려 하기에 쉽고 간단하게 정

interconnection.tistory.com

 

728x90
반응형

+ Recent posts