bss 영역
data 영역
구분 | 구조체(Struct) | 공용체(Union) |
---|---|---|
메모리 할당 | 각 멤버가 독립적인 메모리 공간을 가짐 | 가장 큰 멤버만큼의 메모리 공간을 공유 |
동시 접근 | 모든 멤버 변수에 동시에 접근 가능 | 한 번에 한 멤버만 접근 가능 |
메모리 크기 | 멤버 변수들의 크기의 합 | 가장 큰 멤버 변수의 크기 |
사용 예시 | 여러 데이터를 동시에 저장하고 사용할 때 | 여러 데이터 중 하나만 사용할 때 |
Short version: "page" means "virtual page" (i.e. a chunk of virtual address space) and "page frame" means "physical page" (i.e. a chunk of physical memory).
https://cyber0946.tistory.com/81
write-through : CPU가 데이터를 사용하면 캐시에 저장되게 되는데, 데이터가 캐시 됨과 동시에 주기억장치 또는 디스크로 기입되는 방식을 지원하는 구조의 캐시이다. 즉, 캐시와 메모리 둘다에 업데이트.
write-back : CPU 데이터를 사용할 때 데이터는 먼저 캐시로 기록되는데, 캐시 내에 일시적으로 저장된 후에 블록 단위에 캐시로부터 해제되는 때(캐시 안에 있는 내용을 버릴시)에만 주기억장치 또는 보조기억장치에 기록되는 방식이다. 즉, 데이터를 쓸 때 메모리에는 쓰지 않고 캐시에만 업데이트를 하다가 필요할 때에만 주기억장치나 보조기억장치에 기록하는 방법.
비동기 작업 : 다른 함수 끝나는 거 기다리지 않고 같이 병렬적으로 실행되는거
callback : 특정 작업이나 함수가 끝났을 때 실행되도록 미리 전달된 함수
왼쪽에 있는거 오른쪽처럼 만드는거
cardianlity : 유니크한 값이 얼마나 많이 있느냐
cardinality 높으면 bitmap 적합하지 않음
칼럼의 값들을 행으로 만든 다음 해당되면 1, 아니면 0으로 할당.
https://mangkyu.tistory.com/102
넣으려는 값에 대응되는 인덱스를 함수 넣어서 구한다.
겹치면 분리 연결법(Separate Chaining) 또는 개방 주소법(Open Addressing)
동일한 인덱스 가진 데이터에 대해 자료구조를 활용해 추가 메모리를 사용하여 다음 데이터의 주소를 저장
비어있는 해시 테이블의 공간을 활용
include/vm/vm.h
enum vm_type : 페이지 종류 지정?
struct page : 이미 정의돼있는 거 건들지 말라고 함
페이지와 관련된 동작들을 page_operations라는 구조체로 묶어놓음
vm/vm.c
페이지 만들고 싶으면 직접 만들지 말고 vm_alloc_page_with_initializer
나 vm_alloc_page
을 통해서 해라
thread에는 supplemental_page_table라는 타입을 가진 spt라는 변수가 있는데, 이건 쓰레드가 갖고 있는 모든 가상 메모리를 위한 테이블. 비어있어서 직접 만들어야 됨.
spt_find_page : spt에서 가상 주소를 찾아서 페이지를 돌려준다.
include/vm/uninit.h
struct uninit_page : Lazy loading(demand paging)을 위한 구조체. 아직 물리 주소 매핑 안된 놈을 의미.
vm/uninit.c
page fault 나기 전 페이지 상태인 uninit page에 대한 함수들 있음
vm/anon.c
파일과 관련 없는 non-disk image(익명 페이지)에 대한 함수들 있음.
페이지가 빠질 때 스왑 영역으로 빠지게 해야될듯.
vm/file.c
file-backed file object들에 대한 함수들.
페이지 들어올 때 파일에서 읽어오고 빠질 땐 파일에 저장한다.
devices/block.c
는 없고 disk.c로 바뀌었다고 함.
이 이미지에서 보여주는 것은 가상 주소가 4단계의 페이지 테이블 탐색을 통해 물리 주소로 변환되는 과정입니다. 각 단계에서 9비트씩 사용하여 페이지 테이블을 탐색하고, 마지막 12비트는 물리적 페이지에서의 오프셋을 나타냅니다.
이 과정은 Intel x86-64 아키텍처의 가상 메모리 관리 방식에서 필수적인 부분이며, 이를 통해 CPU는 가상 주소를 물리적 메모리에 매핑할 수 있습니다.
PML4 (Page Map Level 4)는 Intel x86-64 아키텍처에서 사용하는 4단계 페이지 테이블 구조의 최상위 단계입니다.
그렇게 하면 느려진다고 아는데 왜 굳이 여러 단계로 나누는 거임
가상 메모리 주소 공간은 모든 영역을 사용하는 것이 아니라, 특정 부분만 실제로 사용될 수 있습니다. 이 경우, 여러 단계를 나누면 사용하지 않는 부분에 대한 페이지 테이블을 할당할 필요가 없어 메모리 공간을 절약할 수 있습니다.
페이지 테이블을 여러 단계로 나누는 것은 추가적인 메모리 참조를 요구하기 때문에 성능이 다소 떨어질 수 있습니다. 그러나 현대 CPU는 이러한 성능 저하를 완화하기 위해 TLB(Translation Lookaside Buffer)라는 고속 캐시를 사용하여 페이지 테이블 참조를 캐싱합니다.
TLB는 페이지 테이블의 여러 단계 참조에서 발생할 수 있는 성능 저하를 줄이는 데 중요한 역할을 합니다. 자주 사용하는 페이지에 대한 매핑 정보를 TLB에 저장함으로써, 페이지 테이블을 반복적으로 참조할 필요 없이 빠르게 주소 변환이 가능합니다.
12 11 0
+-----------------------+-----------+
| Frame Number | Offset |
+-----------------------+-----------+
Physical Address
물리 프레임(physical frame) 또는 페이지 프레임(page frame)이라고 불리는 프레임은, 물리 메모리 상의 연속적인 영역이다.
페이지와 동일하게, 프레임은 페이지 사이즈여야 하고 페이지 크기에 정렬되어 있어야 한다.
그러므로 64비트 물리주소는 프레임 넘버와 프레임 오프셋(또는 그냥 오프셋)으로 나누어질 수 있다.
x86-64는 물리 주소 접근 못하게 하는데 Pintos는 커널 가상 메모리를 물리 메모리에 직접 매핑해서 해결한다.
커널 가상 메모리 n번째 페이지는 물리 메모리 n번째 프레임에 매핑돼있다.
커널 가상 메모리 통하면 프레임에 접근할 수 있다.
Pintos는 물리 주소와 커널 가상 주소 사이를 변환하는 함수 제공한다.
aliases : 동일한 프레임을 참조하는 두개 이상의 페이지
CPU는 페이지 테이블의 accessed bit를 1로 설정하고, 페이지에 쓸 때마다 dirty bit를 1로 설정.
CPU는 이 비트들을 절대 0으로 다시 리셋하지 않지만 운영체제는 이를 0으로 리셋할 수도 있음.
aliased 된 프레임에 접근이 발생하면, access bit와 dirty bit는 해당 프레임에 접근한 페이지의 페이지 엔트리 에서만 갱신됨.
해당 프레임을 참조하는 다른 페이지(aliases) 의 access bit와 dirty bit는 업데이트 되지 않음.
Pintos는 threads/mmu.c안에 페이지 테이블을 관리하는 코드를 제공
+----------+
.--------------->|Page Table|-----------.
/ +----------+ |
| 12 11 0 V 12 11 0
+---------+----+ +---------+----+
| Page Nr | Ofs| |Frame Nr | Ofs|
+---------+----+ +---------+----+
Virt Addr | Phys Addr ^
\_______________________________________/
페이지 넘버는 페이지 테이블을 통해 프레임 넘버로 변환되고
프레임 넘버랑 같이 있는 오프셋으로 물리 주소 획득
구현을 위한 가능한 선택지로는 배열, 리스트, 비트맵, 해시 테이블
def combi4(cnt): return cnt*(cnt-1)*(cnt-2)*(cnt-3)/24
def combi3(cnt): return cnt*(cnt-2)*(cnt-3)/6
def case(cnt):
# 해당 자리수를 보존한 경우의 수와 보존하지 않은 경우의 수들을 합쳐야 함
# 456789를 예로 들면, (1) 4 그대로, (2) 1 떨어진 3과 1, (3) 그냥 2, (4) 아예 사라짐
# (1), (2), (3)에 대한 경우의 수를 구했으면 다음 자릿수인 (4)로 넘어가야 함
if cnt == 4: return 1
global N
L=len(N)
num=int(N[L-cnt])
result=0
if num!=2:
result+=case(cnt-1)*combi4(cnt-2) # (1) 4 그대로
if num!=1:
result+=(num-2)*combi4(cnt-1)*(9**(cnt-5)) # (2) 1떨어진 숫자들
result+=combi3(cnt-1)*(9**(cnt-4)) # (3) 그냥 2
return result
N=input()
cnt=len(N)
result=case(cnt)
# result+=combi4(cnt-1)*(9**(cnt-5)) # (4) 그냥 0 (아예 사라짐)
print(result)
보존과 비보존 경우의 수를 구해야된다는 것과
단순히 남은 자리수를 고르는게 아니라 2,0,2,3의 숫자가 들어갈 수 있는지 고려해야 된다는 것까진 알아냄