<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko-KR, en-US"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://hwanlog.me/feed.xml" rel="self" type="application/atom+xml" /><link href="http://hwanlog.me/" rel="alternate" type="text/html" hreflang="ko-KR, en-US" /><updated>2026-06-01T01:35:54+00:00</updated><id>http://hwanlog.me/feed.xml</id><title type="html">hwan log</title><subtitle>기술블로그
</subtitle><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><entry><title type="html">베스핀글로벌 참여 전날</title><link href="http://hwanlog.me/blog/devlog/%EB%B2%A0%EC%8A%A4%ED%95%80%EA%B8%80%EB%A1%9C%EB%B2%8C%EC%9D%B8%ED%84%B4%EC%B0%B8%EC%97%AC%EC%A0%84%EB%82%A0/" rel="alternate" type="text/html" title="베스핀글로벌 참여 전날" /><published>2026-05-31T00:00:00+00:00</published><updated>2026-05-31T00:00:00+00:00</updated><id>http://hwanlog.me/blog/devlog/%EB%B2%A0%EC%8A%A4%ED%95%80%EA%B8%80%EB%A1%9C%EB%B2%8C%EC%9D%B8%ED%84%B4%EC%B0%B8%EC%97%AC%EC%A0%84%EB%82%A0</id><content type="html" xml:base="http://hwanlog.me/blog/devlog/%EB%B2%A0%EC%8A%A4%ED%95%80%EA%B8%80%EB%A1%9C%EB%B2%8C%EC%9D%B8%ED%84%B4%EC%B0%B8%EC%97%AC%EC%A0%84%EB%82%A0/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#부트캠프-수료-후-취준" id="markdown-toc-부트캠프-수료-후-취준">부트캠프 수료 후 취준</a></li>
  <li><a href="#개발에-처음-입문하게-된-계기" id="markdown-toc-개발에-처음-입문하게-된-계기">개발에 처음 입문하게 된 계기</a></li>
  <li><a href="#나는-무엇을-하고-싶을까" id="markdown-toc-나는-무엇을-하고-싶을까">나는 무엇을 하고 싶을까?</a></li>
  <li><a href="#개발자-직군-첫-인턴" id="markdown-toc-개발자-직군-첫-인턴">개발자 직군 첫 인턴</a></li>
</ul>

<h2 id="부트캠프-수료-후-취준">부트캠프 수료 후 취준</h2>
<p>7/31일 크래프톤정글을 수료하고 8월, 9월은 면접일정 때문에 정신없었다.
진행했던 면접들마다 아쉬운 결과를 받으며 약간 고삐를 놓은 느낌이였다.
이후 2026년도에는 다시 개발공부들을 복기하며 사이드프로젝트와 취준까지 병행하며 지내왔다.
취준이 길어지니 공백기간을 가지는게 걱정이 되어 직무를 확장해서 서버, 모니터링, C++까지 면접을 보았고,
합격소식을 들을 수 있었다. 다만 공백기를 없애고자 별로 관심없는 직무에 시간을 쏟는게 맞는지 의문이 생겼다.</p>

<h2 id="개발에-처음-입문하게-된-계기">개발에 처음 입문하게 된 계기</h2>
<p>대학교때 코딩으로 무에서 유를 만들어내는게 흥미로워 개발에 관심을 가지게 되었고 우연히 참여한 교내 창업캠프에서
학우 두명과 돈 좀 벌어보자! 100억으로 엑싯하자는 목표를 가지고 함께 창업동아리를 만들며 창업활동도 하게되었다.
창업학 교수님 산하로 들어가 국가지원사업까지 경험했지만 점점 개발과는 멀어지는 것 같아 졸업반때 창업을 그만두었다.
이후 졸업을 하며 창업활동으로 전공수업을 듣지 못한 것이 아쉬워 졸업 후 바로 크래프톤정글이란 부트캠프에 참여했다.
low레벨의 cs개념부터 알고리즘, 개발지(준비생)들과 협업활동까지 정말 나에겐 값진 시간이였고 개발자커리어로 본다면 대학교4년보다 더 의미있었다.</p>

<h2 id="나는-무엇을-하고-싶을까">나는 무엇을 하고 싶을까?</h2>
<p>창업을 그만두긴 했지만 싫어한 것은 아니였다. 1년반이란 기간동안 창업활동을 하며 비즈니스 구조를 이해하고 아이디어를 수립해 사업계획서를 작성해보며 학생인 내가 스스로 수익구조를 만들어 보는 경험에 빠져들었었다.
나는 내가 개발한 서비스로 많은 돈을 벌어보고싶다. 그리고 많은 사람들이 이용하는 서비스를 운영해보고 싶다.
그렇다면 내가 가야할 길은 1인창업이다..ㅋㅋㅋㅋㅋ 요즘 ai가 잘 되어있어서 정말 가능할 일인것도 같다.
그래도 현재 취업시장에서 어떤 문을 두드릴지 결정해야한다.
ai기술로 서비스를 만들거나 사용자트래픽이 많은 서비스에서 개발일을 할 수 있는 직무를 찾아보았고 지원했다.
인턴, 청년일경험, 신입사원등 다양하게 지원을 했고 청년일겸험으로 베스핀글로벌의 GenAI직무에 합류하게 되었다.</p>

<h2 id="개발자-직군-첫-인턴">개발자 직군 첫 인턴</h2>
<p>청년일경험은 정부에서 진행하는 인턴형이면서 근무시간이 3시간이나 적은 5시간이다.(8시간-&gt;5시간)
그래도 개발자직무로 인턴을 할 수 있는게 흥미로우면서 기대된다.
앞으로는 내가 하기에 달린 것 같다. 현재 개발시장은 너무 빠르게 앞서나가고 있다. 
ai가 나보다 코드를 잘 짜는 것 같다. 결국은 이 개발시장의 흐름을 잘 파악하고 ai를 업무나 개발에 잘 다루는 사람이
가치있는 개발자가 될 것 이라고 생각한다. 
나의 목표인 사람들에게 가치있는 서비스를 제공하는 개발자가 되어보자. 내일 첫 출근 화이팅.</p>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="devlog" /><category term="베스핀글로벌_GanAi" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">암호학 기초</title><link href="http://hwanlog.me/blog/cs/cryptography/" rel="alternate" type="text/html" title="암호학 기초" /><published>2026-01-22T00:00:00+00:00</published><updated>2026-01-22T00:00:00+00:00</updated><id>http://hwanlog.me/blog/cs/cryptography</id><content type="html" xml:base="http://hwanlog.me/blog/cs/cryptography/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#왜-암호화가-필요한가" id="markdown-toc-왜-암호화가-필요한가">왜 암호화가 필요한가?</a></li>
  <li><a href="#정보보안-3요소-cia-triad" id="markdown-toc-정보보안-3요소-cia-triad">정보보안 3요소 (CIA Triad)</a></li>
  <li><a href="#세-가지-핵심-개념" id="markdown-toc-세-가지-핵심-개념">세 가지 핵심 개념</a></li>
  <li><a href="#암호화-방식" id="markdown-toc-암호화-방식">암호화 방식</a>    <ul>
      <li><a href="#양방향-암호화" id="markdown-toc-양방향-암호화">양방향 암호화</a>        <ul>
          <li><a href="#대칭키-방식" id="markdown-toc-대칭키-방식">대칭키 방식</a></li>
          <li><a href="#비대칭키-방식" id="markdown-toc-비대칭키-방식">비대칭키 방식</a></li>
        </ul>
      </li>
      <li><a href="#단방향-암호화-해시" id="markdown-toc-단방향-암호화-해시">단방향 암호화 (해시)</a></li>
    </ul>
  </li>
  <li><a href="#실생활-적용" id="markdown-toc-실생활-적용">실생활 적용</a></li>
  <li><a href="#핵심-요약" id="markdown-toc-핵심-요약">핵심 요약</a></li>
</ul>

<h2 id="왜-암호화가-필요한가">왜 암호화가 필요한가?</h2>

<p>인터넷으로 데이터를 주고받을 때 세 가지 위협이 존재한다.</p>

<ul>
  <li><strong>도청(Sniffing)</strong> — 전송 중인 데이터를 몰래 엿봄</li>
  <li><strong>위·변조(Tampering)</strong> — 내용을 바꿔치기함</li>
  <li><strong>도용(Identity Theft)</strong> — 다른 사람인 척 속임</li>
</ul>

<hr />

<h2 id="정보보안-3요소-cia-triad">정보보안 3요소 (CIA Triad)</h2>

<table>
  <thead>
    <tr>
      <th>요소</th>
      <th>의미</th>
      <th>달성 방법</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Confidentiality</strong> (기밀성)</td>
      <td>남이 보지 못하게</td>
      <td>암호화 (Encryption)</td>
    </tr>
    <tr>
      <td><strong>Integrity</strong> (무결성)</td>
      <td>내용이 바뀌지 않았음을 보장</td>
      <td>해시 + 전자서명</td>
    </tr>
    <tr>
      <td><strong>Availability</strong> (가용성)</td>
      <td>필요할 때 언제든 사용 가능</td>
      <td>서버 안정성, DDoS 방어</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p><strong>+ 인증(Authentication)</strong>: 권한 있는 사람만 접근 가능하게 함</p>
</blockquote>

<hr />

<h2 id="세-가지-핵심-개념">세 가지 핵심 개념</h2>

<table>
  <thead>
    <tr>
      <th>개념</th>
      <th>설명</th>
      <th>방향</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>암호화 (Encryption)</strong></td>
      <td>데이터를 읽을 수 없게 변환</td>
      <td>복호화(Decryption) 가능</td>
    </tr>
    <tr>
      <td><strong>해시 (Hash)</strong></td>
      <td>입력값을 고정 길이 “지문”으로 변환</td>
      <td>단방향, 되돌릴 수 없음</td>
    </tr>
    <tr>
      <td><strong>전자서명 (Digital Signature)</strong></td>
      <td>메시지에 서명을 붙여 발신자·위조 여부 검증</td>
      <td>비대칭키 기반</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="암호화-방식">암호화 방식</h2>
<p><img src="/assets/img/blog/security/암호화방식.png" alt="타임라인" /></p>
<h3 id="양방향-암호화">양방향 암호화</h3>

<blockquote>
  <p>암호화 + 복호화 모두 가능 → <strong>기밀성</strong> 목적</p>
</blockquote>

<h4 id="대칭키-방식">대칭키 방식</h4>

<ul>
  <li>암호화·복호화에 <strong>동일한 키</strong> 사용</li>
  <li>빠르지만, 키를 상대에게 안전하게 전달하는 문제가 있음</li>
  <li>대표 알고리즘: <strong>AES</strong>, Twofish, Blowfish, DES, 3DES</li>
</ul>

<h4 id="비대칭키-방식">비대칭키 방식</h4>

<ul>
  <li><strong>공개키(Public Key)</strong> 와 <strong>비공개키(Private Key)</strong> 쌍 사용</li>
  <li>공개키로 암호화 → 비공개키로만 복호화 (반대도 성립)</li>
  <li>키를 공개해도 안전하게 통신 가능</li>
  <li>대표 알고리즘: <strong>RSA</strong></li>
</ul>

<p>[전자서명 흐름]</p>

<p><img src="/assets/img/blog/security/전자서명%20동작%20원리.png" alt="타임라인" /></p>

<blockquote>
  <p><strong>전자서명</strong>: 발신자가 비공개키로 내용에 서명 → 수신자는 공개키로 서명을 복호화해 내용과 대조 → 일치하면 진본·발신자 확인</p>
</blockquote>

<hr />

<h3 id="단방향-암호화-해시">단방향 암호화 (해시)</h3>

<blockquote>
  <p>복호화 불가 → <strong>무결성</strong> 목적</p>
</blockquote>

<ul>
  <li>입력값이 조금만 달라져도 완전히 다른 해시값 출력</li>
  <li>비밀번호 저장, 파일 무결성 검증에 사용</li>
  <li>대표 알고리즘: <strong>SHA-256</strong>, SHA-512, MD5, SHA-1</li>
</ul>

<hr />

<h2 id="실생활-적용">실생활 적용</h2>

<table>
  <thead>
    <tr>
      <th>상황</th>
      <th>암호화 방식</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>HTTPS</strong></td>
      <td>비대칭키로 세션키 교환 → AES(대칭키)로 데이터 암호화</td>
    </tr>
    <tr>
      <td><strong>비밀번호 저장</strong></td>
      <td>해시(SHA 등)로 저장, 복원 불가 → 비교만 함</td>
    </tr>
    <tr>
      <td><strong>E2EE 메신저</strong> (카카오 비밀채팅, WhatsApp)</td>
      <td>종단간 암호화, 서버 관리자도 내용 열람 불가</td>
    </tr>
    <tr>
      <td><strong>파일/USB 암호화</strong></td>
      <td>AES 기반 대칭키 방식</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="핵심-요약">핵심 요약</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>암호화 방식
├── 양방향 (복호화 가능) — 기밀성
│   ├── 대칭키: 같은 키 사용 → AES, DES
│   └── 비대칭키: 공개키/비공개키 쌍 → RSA, 전자서명
└── 단방향 (복호화 불가) — 무결성
    └── 해시: SHA-256, MD5
</code></pre></div></div>

<blockquote>
  <p>참고 영상: <a href="https://www.youtube.com/playlist?list=PLuHgQVnccGMD-9lk4xmb6EG1XK1OmwC3u">생활코딩 암호학</a></p>
</blockquote>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="cs" /><category term="보안" /><summary type="html"><![CDATA[crypto(비밀) + graphy(방법) — 핵심만 빠르게]]></summary></entry><entry><title type="html">HTTP vs HTTPS — SSL/TLS 정리</title><link href="http://hwanlog.me/blog/cs/HTTPS/" rel="alternate" type="text/html" title="HTTP vs HTTPS — SSL/TLS 정리" /><published>2026-01-15T00:00:00+00:00</published><updated>2026-01-15T00:00:00+00:00</updated><id>http://hwanlog.me/blog/cs/HTTPS</id><content type="html" xml:base="http://hwanlog.me/blog/cs/HTTPS/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#http-vs-https" id="markdown-toc-http-vs-https">HTTP vs HTTPS</a></li>
  <li><a href="#암호화-계층의-역사" id="markdown-toc-암호화-계층의-역사">암호화 계층의 역사</a>    <ul>
      <li><a href="#ssl-secure-sockets-layer" id="markdown-toc-ssl-secure-sockets-layer">SSL (Secure Sockets Layer)</a></li>
      <li><a href="#tls-transport-layer-security" id="markdown-toc-tls-transport-layer-security">TLS (Transport Layer Security)</a></li>
    </ul>
  </li>
  <li><a href="#타임라인-요약" id="markdown-toc-타임라인-요약">타임라인 요약</a></li>
  <li><a href="#핵심-정리" id="markdown-toc-핵심-정리">핵심 정리</a>    <ul>
      <li><a href="#tls-13의-주요-개선점" id="markdown-toc-tls-13의-주요-개선점">TLS 1.3의 주요 개선점</a></li>
    </ul>
  </li>
</ul>

<h2 id="http-vs-https">HTTP vs HTTPS</h2>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>HTTP</th>
      <th>HTTPS</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>암호화</td>
      <td>없음 (평문 전송)</td>
      <td>있음 (TLS 계층 추가)</td>
    </tr>
    <tr>
      <td>포트</td>
      <td>80</td>
      <td>443</td>
    </tr>
    <tr>
      <td>보안</td>
      <td>도청·변조 위험</td>
      <td>기밀성·무결성 보장</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="암호화-계층의-역사">암호화 계층의 역사</h2>

<h3 id="ssl-secure-sockets-layer">SSL (Secure Sockets Layer)</h3>

<p>Netscape가 1990년대에 개발한 최초의 암호화 통신 프로토콜.</p>

<table>
  <thead>
    <tr>
      <th>버전</th>
      <th>연도</th>
      <th>현재 상태</th>
      <th>비고</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>SSL 1.0</td>
      <td>-</td>
      <td>-</td>
      <td>공개되지 않음</td>
    </tr>
    <tr>
      <td>SSL 2.0</td>
      <td>1995</td>
      <td><strong>사용 금지</strong></td>
      <td>구조적 결함, TLS에서 협상 금지 (RFC 6176)</td>
    </tr>
    <tr>
      <td>SSL 3.0</td>
      <td>1996</td>
      <td><strong>사용 금지</strong></td>
      <td>POODLE 공격(2014)으로 폐기 (RFC 7568)</td>
    </tr>
  </tbody>
</table>

<h3 id="tls-transport-layer-security">TLS (Transport Layer Security)</h3>

<p>SSL의 후속 표준. IETF가 관리. 현재 유일하게 사용되는 프로토콜.</p>

<table>
  <thead>
    <tr>
      <th>버전</th>
      <th>연도</th>
      <th>RFC</th>
      <th>현재 상태</th>
      <th>핵심 변경점</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>TLS 1.0</td>
      <td>1999</td>
      <td>RFC 2246</td>
      <td><strong>2021년 폐기</strong></td>
      <td>SSL 3.0 표준화. BEAST 공격(2011)으로 퇴출</td>
    </tr>
    <tr>
      <td>TLS 1.1</td>
      <td>2006</td>
      <td>RFC 4346</td>
      <td><strong>2021년 폐기</strong></td>
      <td>CBC에 명시적 IV 도입. RFC 8996으로 폐기</td>
    </tr>
    <tr>
      <td>TLS 1.2</td>
      <td>2008</td>
      <td>RFC 5246</td>
      <td><strong>현역</strong> (1.3 권장)</td>
      <td>AEAD(AES-GCM) 등 현대 암호 도입</td>
    </tr>
    <tr>
      <td>TLS 1.3</td>
      <td>2018</td>
      <td>RFC 8446</td>
      <td><strong>최신 권장</strong></td>
      <td>핸드셰이크 간소화(1-RTT), RSA 키교환·CBC 제거</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="타임라인-요약">타임라인 요약</h2>

<p><img src="/assets/img/blog/security/svg_타임라인.png" alt="타임라인" /></p>

<blockquote>
  <p>2021년 RFC 8996으로 TLS 1.0 / 1.1이 공식 폐기됨</p>
</blockquote>

<hr />

<h2 id="핵심-정리">핵심 정리</h2>

<ul>
  <li><strong>SSL은 사라진 옛 프로토콜</strong> — SSL 2.0/3.0 모두 사용 금지</li>
  <li><strong>TLS만 현재 유효</strong> — 그중에서도 TLS 1.2 / TLS 1.3만 써야 함</li>
  <li><strong>“SSL 인증서”는 관행적 명칭</strong> — 실제로는 TLS 인증서가 맞는 말</li>
</ul>

<h3 id="tls-13의-주요-개선점">TLS 1.3의 주요 개선점</h3>

<ul>
  <li>핸드셰이크가 1-RTT로 단순화 → 연결 속도 향상</li>
  <li>Forward Secrecy(FS)가 기본 적용</li>
  <li>취약한 암호 방식 제거: RSA 키교환, CBC 모드, RC4</li>
  <li>0-RTT 재개 지원 (단, 재생 공격 주의)</li>
</ul>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="cs" /><category term="보안" /><summary type="html"><![CDATA[HTTPS의 암호화 계층, SSL과 TLS의 역사와 차이를 한눈에 정리]]></summary></entry><entry><title type="html">KRAFTON JUNGLE 16주차 회고</title><link href="http://hwanlog.me/blog/devlog/jungle-16week/" rel="alternate" type="text/html" title="KRAFTON JUNGLE 16주차 회고" /><published>2025-07-31T00:00:00+00:00</published><updated>2025-07-31T00:00:00+00:00</updated><id>http://hwanlog.me/blog/devlog/jungle-16week</id><content type="html" xml:base="http://hwanlog.me/blog/devlog/jungle-16week/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#14주차" id="markdown-toc-14주차">14주차</a></li>
  <li><a href="#나만무" id="markdown-toc-나만무">나만무</a></li>
</ul>

<h2 id="14주차">14주차</h2>
<p>13주차를 마치고 14주차에는 개인 미니 프로젝트 과제가 주어졌다. CRUD기반의 게시판 서비스를 만들라는 과제였다.</p>

<h2 id="나만무">나만무</h2>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="devlog" /><category term="krafton-jungle" /><category term="회고" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://hwanlog.me/assets/img/blog/devlog/jungle5.jpg" /><media:content medium="image" url="http://hwanlog.me/assets/img/blog/devlog/jungle5.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">KRAFTON JUNGLE 12주차 회고</title><link href="http://hwanlog.me/blog/devlog/jungle-12week/" rel="alternate" type="text/html" title="KRAFTON JUNGLE 12주차 회고" /><published>2025-06-14T00:00:00+00:00</published><updated>2025-06-14T00:00:00+00:00</updated><id>http://hwanlog.me/blog/devlog/jungle-12week</id><content type="html" xml:base="http://hwanlog.me/blog/devlog/jungle-12week/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#9주차" id="markdown-toc-9주차">9주차</a></li>
</ul>

<p>8주차를 마치면서 이제 PintOS주간에 들어오게 되었다. 여태까지 해왔던 과정들이 PintOS를 위한 것이었고 이번 과정을 통해 많이 얻고자 노력할 것이다.</p>

<h2 id="9주차">9주차</h2>

<p>이번에는 1주씩 팀이 바뀌는 기존과는 다르게 총 3주동안 할 팀원이 배정되었다.</p>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="devlog" /><category term="krafton-jungle" /><category term="회고" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://hwanlog.me/assets/img/blog/devlog/jungle4.jpg" /><media:content medium="image" url="http://hwanlog.me/assets/img/blog/devlog/jungle4.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Anonymous &amp;amp; File-backed Page</title><link href="http://hwanlog.me/blog/cs/anon-file/" rel="alternate" type="text/html" title="Anonymous &amp;amp; File-backed Page" /><published>2025-06-10T00:00:00+00:00</published><updated>2025-06-10T00:00:00+00:00</updated><id>http://hwanlog.me/blog/cs/anon-file</id><content type="html" xml:base="http://hwanlog.me/blog/cs/anon-file/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#anonymous-page익명-페이지" id="markdown-toc-anonymous-page익명-페이지">Anonymous page(익명 페이지)</a></li>
  <li><a href="#file-backed-page" id="markdown-toc-file-backed-page">File-backed page</a></li>
  <li><a href="#왜-익명과-파일로-나눌까" id="markdown-toc-왜-익명과-파일로-나눌까">왜 ‘익명’과 ‘파일’로 나눌까?</a></li>
  <li><a href="#한-눈에-보는-차이점" id="markdown-toc-한-눈에-보는-차이점">한 눈에 보는 차이점</a></li>
</ul>

<h2 id="anonymous-page익명-페이지">Anonymous page(익명 페이지)</h2>

<blockquote>
  <p>“태어나서 처음으로 0만 담긴 백지장을 받고,
나중에 필요해지면 <strong>스왑장치</strong>에 임시로 메모를 남기는 종이”</p>
</blockquote>

<ol>
  <li>
    <p><strong>정의</strong></p>

    <ul>
      <li><strong>백업 파일이 없는</strong> 사용자 가상 페이지 (어떤 파일에 연결되지 않고, 콘텐츠를 오직 프로세스가 직접 만든다)</li>
    </ul>
  </li>
  <li>
    <p><strong>주로 쓰이는 곳</strong></p>

    <ul>
      <li>
        <p>힙(Heap) - <code class="language-plaintext highlighter-rouge">malloc()</code>, <code class="language-plaintext highlighter-rouge">brk()/sbrk()</code>로 확장된 영역</p>
      </li>
      <li>
        <p>스택(Stack) - 함수 호출 · 지역 변수 · 스택 자동 확장</p>
      </li>
      <li>
        <p>BSS - 초기값이 0인 전역/정적 변수</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>초기 로딩</strong></p>

    <ol>
      <li>
        <p>페이지 폴트 발생</p>
      </li>
      <li>
        <p>커널이 새 프레임을 할당(palloc 등)</p>
      </li>
      <li>
        <p><strong>Zero-fill</strong> → 프레임 전체를 0으로 채움</p>
      </li>
      <li>
        <p>PTE(Present = 1…) 갱신</p>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>추방(Eviction) &amp; 복원</strong></p>

    <ul>
      <li>
        <p>프레임 부족 시 <strong>swap device</strong>에 4KB 블록 단위로 기록</p>
      </li>
      <li>
        <p><code class="language-plaintext highlighter-rouge">page-&gt;anon.swap_slot</code>에 위치 기록</p>
      </li>
      <li>
        <p>다시 접근하면 swap 슬롯에서 읽어 프레임 재생성(<code class="language-plaintext highlighter-rouge">swap_in</code>)</p>
      </li>
    </ul>
  </li>
</ol>

<p><strong>특징 &amp; 장단점</strong></p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">장점</th>
      <th style="text-align: left">단점</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">① 생성·파괴가 빠르고 단순 (Zero-fill)</td>
      <td style="text-align: left">① 스왑 I/O 부담 (백업이 swap뿐)</td>
    </tr>
    <tr>
      <td style="text-align: left">② 프로세스마다 독립적인 공간</td>
      <td style="text-align: left">② 다른 프로세스와 <strong>공유 불가</strong>-동일 내용이라도 중복</td>
    </tr>
  </tbody>
</table>

<p>Anonymous page는 “이 페이지를 원래 복원시켜 줄 파일이 없다”는 뜻이고, 그래서 스왑 장치가 실질적 백업이다.</p>

<h2 id="file-backed-page">File-backed page</h2>

<blockquote>
  <p>“이미 <strong>원본 파일</strong>이 존재하는 종이의 사본.
필요하면 원본을 다시 떼어오면 되고, 수정하면 원본에 덮어쓰거나 폐기”</p>
</blockquote>

<ol>
  <li>
    <p><strong>정의</strong></p>

    <ul>
      <li><strong>파일 시스템 블록</strong>을 근간(backup store)으로 삼는 가상 페이지 (실행 파일 · 공유 라이브러리 · <code class="language-plaintext highlighter-rouge">mmap()</code>한 일반 파일 등)</li>
    </ul>
  </li>
  <li>
    <p><strong>주로 쓰이는 곳</strong></p>

    <ul>
      <li>
        <p><strong>코드(Text) / 데이터(Data) 세그먼트</strong> - ELF 로더가 LAZY-LOAD</p>
      </li>
      <li>
        <p><strong>공유 라이브러리</strong> - 여러 프로세스가 같은 read-only 프레임 공유</p>
      </li>
      <li>
        <p><strong>Memory-Mapped File</strong> - <code class="language-plaintext highlighter-rouge">mmap()</code>으로 매핑해 직접 버퍼처럼 사용</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>초기 로딩</strong></p>

    <ol>
      <li>
        <p>페이지 폴트 발생</p>
      </li>
      <li>
        <p>새 프레임 할당</p>
      </li>
      <li>
        <p><strong>file_read_at()</strong>으로 해당 오프셋 데이터 읽어 채움</p>

        <ul>
          <li>남는 바이트는 0-fill</li>
        </ul>
      </li>
      <li>
        <p>PTE 갱신</p>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>추방(Eviction) &amp; 복원</strong></p>
  </li>
</ol>

<table>
  <thead>
    <tr>
      <th style="text-align: center">상태</th>
      <th style="text-align: center">동작</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center"><strong>Clean</strong>(수정 안됨)</td>
      <td style="text-align: center">프레임을 그냥 버림 → 나중에 다시 파일에서 읽으면 끝</td>
    </tr>
    <tr>
      <td style="text-align: center"><strong>Dirty</strong>(수정됨)</td>
      <td style="text-align: center">쓰기 가능한 매핑이면 파일에 <strong>write-back</strong><br />읽기 전용 매핑에서 dirty가 날 일 없도록 PTE R/W 비트를 미리 제한</td>
    </tr>
  </tbody>
</table>

<p><strong>특징 &amp; 장단점</strong></p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">장점</th>
      <th style="text-align: left">단점</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">① <strong>Clean</strong>페이지는 I/O 없이 드롭 → 캐시처럼 동작<br />② 여러 프로세스 간 공유·중복 제거 가능 (코드 세그먼트)</td>
      <td style="text-align: left">① Dirty 페이지 관리 복잡 (write-back 시점·동기화)<br />② 파일 시스템 락·I/O 지연 영향</td>
    </tr>
  </tbody>
</table>

<p>File-backed page는 “이미 파일이 백업 스토어로 존재한다”는 뜻이고, OS는 이를 활용해 I/O 횟수를 줄이고, 여러 프로세스가 같은 데이터(코드 등)를 안전하게 공유할 수 있다.</p>

<h2 id="왜-익명과-파일로-나눌까">왜 ‘익명’과 ‘파일’로 나눌까?</h2>

<ol>
  <li>
    <p><strong>백업 스토어 차이</strong></p>

    <ul>
      <li>
        <p>익명 : 원본이 없으므로 스왑이 유일한 백업</p>
      </li>
      <li>
        <p>파일 : 이미 디스크에 존재 → 불필요 I/O 줄이기</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>보호 및 공유 모델</strong></p>

    <ul>
      <li>
        <p>파일 기반 read-only 코드는 모든 프로세스가 하나의 물리 프레임 공유 → 메모리 절약</p>
      </li>
      <li>
        <p>익명은 변경이 빈번 · 사적이라 안전하게 분리</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>성능 최적화</strong></p>

    <ul>
      <li>
        <p>Clean file page drop → 페이지 캐시 hit/evict가 빠름</p>
      </li>
      <li>
        <p>익명은 zero-fill이 간단하고 빠름</p>
      </li>
    </ul>
  </li>
</ol>

<blockquote>
  <p>즉, <strong>“누가 너의 원본을 책임지냐?”</strong>에 따라 정책이 갈라진다
“원본 없음 → 익명 + 스왑”
“원본 파일 → 파일 + 캐시/write-back”</p>
</blockquote>

<h2 id="한-눈에-보는-차이점">한 눈에 보는 차이점</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">구분</th>
      <th style="text-align: left">Anonymous page</th>
      <th style="text-align: left">File-backed page</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">초기 내용</td>
      <td style="text-align: left">0으로 채우거나(즉시 zero-fill) swap 공간에서 가져옴</td>
      <td style="text-align: left">실제 파일 블록(ELF 텍스트/데이터, mmap)</td>
    </tr>
    <tr>
      <td style="text-align: center">영속성(Persistence)</td>
      <td style="text-align: left">프로세스가 끝나면 사라짐. 변경분을 별도로 저장하지 않는 한 디스크에 남지 않음</td>
      <td style="text-align: left">원본 파일이 ‘근본’이므로, 읽기 전용이면 버려도 되고, 쓰기 가능 매핑이면 dirty 페이지를 파일에 write-back 해야 함</td>
    </tr>
    <tr>
      <td style="text-align: center">교체(Eviction)</td>
      <td style="text-align: left">프레임이 부족하면 <strong>swap device</strong>(swap disk)의 빈 슬롯에 페이지 전체를 기록</td>
      <td style="text-align: left">프레임이 부족하면<br /><strong>clean</strong> 페이지 → 그냥 버림(다시 파일에서 읽으면 됨)<br /><strong>dirty</strong>페이지 → 파일에 쓰거나, 쓰기 권한 없는 매핑이면 우선 swap 영역 사용 가능</td>
    </tr>
    <tr>
      <td style="text-align: center">대표 영역</td>
      <td style="text-align: left">Heap, user stack, brk/sbrk로 늘어난 익명 메모리, BSS</td>
      <td style="text-align: left">실행 파일 코드·데이터, 공유 라이브러리, mmap()된 보통 파일들</td>
    </tr>
    <tr>
      <td style="text-align: center">PintOS <code class="language-plaintext highlighter-rouge">page-&gt;operations</code></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">anon_page_ops</code> → <code class="language-plaintext highlighter-rouge">swap_in</code>, <code class="language-plaintext highlighter-rouge">swap_out</code>, <code class="language-plaintext highlighter-rouge">destroy</code></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">file_page_ops</code> → <code class="language-plaintext highlighter-rouge">swap_in</code>(=file_read_at), <code class="language-plaintext highlighter-rouge">swap_out</code>(dirty이면 file_write_at), <code class="language-plaintext highlighter-rouge">destroy</code></td>
    </tr>
    <tr>
      <td style="text-align: center">스왑 슬롯 필요?</td>
      <td style="text-align: left">예 (page-&gt;anon.swap_slot)</td>
      <td style="text-align: left">대게 필요 없음(파일이 백업 스토어). 단, 쓰기 가능 매핑에서 dirty 후 evict 시 swap 사용 가능</td>
    </tr>
  </tbody>
</table>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="cs" /><category term="운영체제" /><summary type="html"><![CDATA[Anonymous page와 File-backed page에 대해서 알아보자]]></summary></entry><entry><title type="html">Lazy Loading</title><link href="http://hwanlog.me/blog/cs/lazy-loading/" rel="alternate" type="text/html" title="Lazy Loading" /><published>2025-06-10T00:00:00+00:00</published><updated>2025-06-10T00:00:00+00:00</updated><id>http://hwanlog.me/blog/cs/lazy-loading</id><content type="html" xml:base="http://hwanlog.me/blog/cs/lazy-loading/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#lazy-loading-이란" id="markdown-toc-lazy-loading-이란">Lazy Loading 이란?</a></li>
  <li><a href="#가상메모리에서의-lazy-loading--demand-paging" id="markdown-toc-가상메모리에서의-lazy-loading--demand-paging">가상메모리에서의 Lazy Loading = Demand Paging</a></li>
  <li><a href="#추가-활용" id="markdown-toc-추가-활용">추가 활용</a></li>
  <li><a href="#장점과-단점" id="markdown-toc-장점과-단점">장점과 단점</a>    <ul>
      <li><a href="#장점" id="markdown-toc-장점">장점</a></li>
      <li><a href="#단점" id="markdown-toc-단점">단점</a></li>
    </ul>
  </li>
  <li><a href="#정리" id="markdown-toc-정리">정리</a></li>
</ul>

<p>먼저 여기서 처음 들어보는 개념이 있다면, <a href="../../computersystem/paging" class="heading flip-title">Paging</a>글에서 개념을 참고해 본다.</p>

<h2 id="lazy-loading-이란">Lazy Loading 이란?</h2>

<blockquote>
  <p>“필요해질 때까지 실제 데이터를 읽어들이지 않고, 최소한의 메타데이터만 준비해 두었다가 첫 접근 시점에 비로소 불러오는 기법”
(메모리·스토리지·웹 모두 같은 핵심 아이디어를 공유합니다.)</p>
</blockquote>

<h2 id="가상메모리에서의-lazy-loading--demand-paging">가상메모리에서의 Lazy Loading = Demand Paging</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">시점</th>
      <th style="text-align: left">커널이 하는 일</th>
      <th style="text-align: left">이득</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">exec 시</td>
      <td style="text-align: left">- 각 세그먼트의 page table entry를 P=0(not-present)로만 채우고<br />- “어느 파일 오프셋에서 몇 바이트를 읽으면 되는지” 보조 정보를 보관</td>
      <td style="text-align: left">- 프로세스 시작 시간이 빨라짐<br />- 실제로 쓰이지 않는 코드는 끝까지 안 올려도 됨</td>
    </tr>
    <tr>
      <td style="text-align: center">첫 접근(Page Fault)</td>
      <td style="text-align: left">1. HW가 페이지 폴트를 발생시켜 커널에 트랩<br />2. 커널 lazy loader가<br />- 파일에서 해당 범위만큼 읽어 오거나(File backed)<br />- 0으로 초기화(Anon page)<br />- <code class="language-plaintext highlighter-rouge">install_page()</code>→P=1로 바꿈<br />3. 사용자 코드 재시작</td>
      <td style="text-align: left">- 실제 사용량만큼만 메모리 소비<br />- I/O 병목이 줄어듬</td>
    </tr>
  </tbody>
</table>

<p>PintOS Project3에서 구현하는 <code class="language-plaintext highlighter-rouge">uninit_new()</code>/<code class="language-plaintext highlighter-rouge">vm_try_handle_fault()</code><strong>흐름</strong>이 정확히 이 구조다. 실행 파일을 로드할 때에는 <code class="language-plaintext highlighter-rouge">lazy_load_segment()</code>를 등록해 두고, 페이지 폴트가 오면 <code class="language-plaintext highlighter-rouge">file_read_at()</code>으로 필요한 바이트만 채운 뒤 PTE를 present로 갱신한다.</p>

<h2 id="추가-활용">추가 활용</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">영역</th>
      <th style="text-align: center">Lazy Loading의 형태</th>
      <th style="text-align: left">주의할 점</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">파일 mmap</td>
      <td style="text-align: center">매핑만 걸어 두고 실제 I/O는 첫 접근 때 수행 → 페이지 캐시에 올라감</td>
      <td style="text-align: left">- Dirty page write-back 정책<br />- <code class="language-plaintext highlighter-rouge">msync</code>, <code class="language-plaintext highlighter-rouge">munmap</code> 시점 처리</td>
    </tr>
    <tr>
      <td style="text-align: center">Copy-on Write(COW)</td>
      <td style="text-align: center">fork후 부모·자식이 같은 물리 페이지 공유하다가 쓰기 폴트 시 복사</td>
      <td style="text-align: left">- PTE의 R/W 비트 관리<br />- race condition 방지 위한 락</td>
    </tr>
    <tr>
      <td style="text-align: center">Web Frontend</td>
      <td style="text-align: center"><code class="language-plaintext highlighter-rouge">&lt;img loading="lazy"&gt;</code>, React lazy import 등</td>
      <td style="text-align: left">- LCP, CLS 같은 Web-Vitals 모니터링</td>
    </tr>
    <tr>
      <td style="text-align: center">모듈/플러그인 Loader</td>
      <td style="text-align: center">필요 함수만 <code class="language-plaintext highlighter-rouge">dlopen()</code>/<code class="language-plaintext highlighter-rouge">LoadLibrary()</code></td>
      <td style="text-align: left">- 호출 경로 예외 처리<br />- 초기화 지연이 성능에 미치는 영향 측정</td>
    </tr>
  </tbody>
</table>

<h2 id="장점과-단점">장점과 단점</h2>

<h3 id="장점">장점</h3>

<ul>
  <li>
    <p>메모리 footpring ↓, 시작 latency ↓</p>
  </li>
  <li>
    <p>I/O를 실제 필요 시점으로 분산해 <strong>burst I/O</strong> 완화</p>
  </li>
  <li>
    <p>COW와 결합하면 fork 성능 개선</p>
  </li>
</ul>

<h3 id="단점">단점</h3>

<ul>
  <li>
    <p>첫 접근 시 <strong>페이지 폴트 오버헤드(context switch + I/O)</strong></p>
  </li>
  <li>
    <p>커널 코드가 더 복잡해지고 동기화 비용 증가</p>
  </li>
  <li>
    <p>예측 불가한 지연이 실시간 워크로드에 영향을 줄 수 있음</p>
  </li>
</ul>

<h2 id="정리">정리</h2>

<p>Lazy Loading = 데이터 · 코드를 <strong>“나중에, 진짜 필요할 때”</strong> 불러오자는 철저한 지연 전략이다. 운영체제에서는 demand paging 형태로 구현되어 프로세스 시작 시간을 줄이고 메모리 자원을 절약한다. PintOS Project3의 핵심 과제이므로, <strong>보조 정보 구조체 설계, PTE 플래그 관리, 동기화</strong>에 특히 신경 쓰자</p>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="cs" /><category term="운영체제" /><summary type="html"><![CDATA[메모리를 무한대로 사용할 수 있을까?]]></summary></entry><entry><title type="html">Page Replacement Policy: 어떤 페이지를 희생시킬까?</title><link href="http://hwanlog.me/blog/cs/page-replacement-policy/" rel="alternate" type="text/html" title="Page Replacement Policy: 어떤 페이지를 희생시킬까?" /><published>2025-06-10T00:00:00+00:00</published><updated>2025-06-10T00:00:00+00:00</updated><id>http://hwanlog.me/blog/cs/page-replacement-policy</id><content type="html" xml:base="http://hwanlog.me/blog/cs/page-replacement-policy/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#1-왜-page-replacement-policy가-필요한가" id="markdown-toc-1-왜-page-replacement-policy가-필요한가">1. 왜 Page Replacement Policy가 필요한가?</a></li>
  <li><a href="#2-정책-설계-시-고려-요소" id="markdown-toc-2-정책-설계-시-고려-요소">2. 정책 설계 시 고려 요소</a></li>
  <li><a href="#3-대표-알고리즘" id="markdown-toc-3-대표-알고리즘">3. 대표 알고리즘</a>    <ul>
      <li><a href="#lru-근사-방법" id="markdown-toc-lru-근사-방법">LRU 근사 방법</a></li>
    </ul>
  </li>
  <li><a href="#4-beladys-anomaly" id="markdown-toc-4-beladys-anomaly">4. Belady’s Anomaly</a></li>
  <li><a href="#5-실제-os-사례" id="markdown-toc-5-실제-os-사례">5. 실제 OS 사례</a></li>
  <li><a href="#6-성능-분석-방법" id="markdown-toc-6-성능-분석-방법">6. 성능 분석 방법</a></li>
  <li><a href="#7-요약" id="markdown-toc-7-요약">7. 요약</a></li>
</ul>

<p>무한대처럼 보이는 가상 메모리도 물리적 한계에 부딪히면 희생양(victim)을 골라야 한다.
그 희생양을 고르는 규칙, Page Replacement Policy를 살펴본다.</p>

<h2 id="1-왜-page-replacement-policy가-필요한가">1. 왜 Page Replacement Policy가 필요한가?</h2>

<p>가상 메모리는 프로세스마다 “거의 무한대”처럼 보이는 주소 공간을 제공하지만, 실제 물리 프레임 수는 제한적이다. 그래서 다음 상황이 생긴다.</p>

<ol>
  <li>page fault가 발생해 새 페이지를 적재해야 한다</li>
  <li>그런데 여유 프레임이 없으면, 커널은 한 프레임을 비워야 한다</li>
  <li>어떤 페이지를 <strong>희생(victim)</strong> 으로 내보낼지 정하는 규칙이 <strong>Page Replacement Policy</strong>다</li>
</ol>

<p>목표는 <strong>디스크 I/O 횟수(=페이지 폴트율)를 최소화</strong>해 전체 성능을 높이는 것이다.</p>

<h2 id="2-정책-설계-시-고려-요소">2. 정책 설계 시 고려 요소</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: left">관점</th>
      <th style="text-align: left">설명</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">효율성</td>
      <td style="text-align: left">낮은 페이지 폴트율, 적은 CPU 오버헤드</td>
    </tr>
    <tr>
      <td style="text-align: left">공정성</td>
      <td style="text-align: left">공유 시 특정 프로세스만 희생되지 않도록</td>
    </tr>
    <tr>
      <td style="text-align: left">Stack Property</td>
      <td style="text-align: left">프레임 수를 늘리면 절대 폴트가 늘지 않는 성질 (OPT·LRU가 가짐)</td>
    </tr>
    <tr>
      <td style="text-align: left">실현 가능성</td>
      <td style="text-align: left">하드웨어 지원(Reference/Dirty 비트) 유무, 구현 복잡도</td>
    </tr>
    <tr>
      <td style="text-align: left">전역 vs 로컬</td>
      <td style="text-align: left">전역(global): 전체 시스템에서 victim 선정 / 로컬(local): fault를 낸 프로세스의 working set 안에서만 선정</td>
    </tr>
  </tbody>
</table>

<h2 id="3-대표-알고리즘">3. 대표 알고리즘</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">알고리즘</th>
      <th style="text-align: left">동작</th>
      <th style="text-align: left">특징</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">OPT / MIN</td>
      <td style="text-align: left">가장 먼 미래에 참조될 페이지 제거</td>
      <td style="text-align: left">이론적 최적. 실현 불가능 → 벤치마킹용 하한선(lower bound)</td>
    </tr>
    <tr>
      <td style="text-align: center">FIFO</td>
      <td style="text-align: left">들어온 순서대로 제거</td>
      <td style="text-align: left">구현 간단. Belady’s Anomaly 발생 가능</td>
    </tr>
    <tr>
      <td style="text-align: center">Second-Chance / Clock</td>
      <td style="text-align: left">FIFO 큐 + 참조 비트(A) 검사. A=1이면 0으로 clear 후 뒤로 회전, A=0이면 victim</td>
      <td style="text-align: left">간단·저렴, LRU 근사</td>
    </tr>
    <tr>
      <td style="text-align: center">LRU</td>
      <td style="text-align: left">가장 오래 사용되지 않은 페이지 제거</td>
      <td style="text-align: left">Stack Property 보장. 정확한 LRU는 하드웨어 타임스탬프 필요 → 보통 근사 사용</td>
    </tr>
    <tr>
      <td style="text-align: center">LFU / NFU</td>
      <td style="text-align: left">누적 참조 횟수 기반 제거</td>
      <td style="text-align: left">“cold yet used” 페이지가 안 쫓겨나는 문제 → aging 필요</td>
    </tr>
    <tr>
      <td style="text-align: center">Working-Set / WSClock</td>
      <td style="text-align: left">최근 Δ 참조 내 사용된 페이지 집합 유지 (WSClock은 Clock에 timestamp 추가)</td>
      <td style="text-align: left">working set 근사, 쓰기 I/O 분산</td>
    </tr>
    <tr>
      <td style="text-align: center">Random</td>
      <td style="text-align: left">무작위 victim</td>
      <td style="text-align: left">LRU 추적 비용이 클 때 사용 (예: 일부 GPU MMU)</td>
    </tr>
  </tbody>
</table>

<h3 id="lru-근사-방법">LRU 근사 방법</h3>

<p>정확한 LRU는 비용이 커서, 실제로는 다음 근사를 쓴다.</p>

<ul>
  <li><strong>N-비트 Aging</strong>: 주기마다 R 비트를 상위로 시프트</li>
  <li><strong>카운터 기반</strong>: 하드웨어가 마지막 접근 시각을 기록 (32/64비트)</li>
  <li><strong>Enhanced Clock / Clock-Pro</strong>: 인접 시계 방식</li>
</ul>

<h2 id="4-beladys-anomaly">4. Belady’s Anomaly</h2>

<p>Stack Property가 없는 FIFO 계열에서 나타나는 현상이다. <strong>프레임을 늘렸는데 오히려 페이지 폴트가 더 많아질 수 있다</strong> (예: 3프레임보다 4프레임이 더 많은 폴트). 정책 선택 시 주의해야 한다.</p>

<h2 id="5-실제-os-사례">5. 실제 OS 사례</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">OS</th>
      <th style="text-align: left">구현 요지</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">Linux (5.x)</td>
      <td style="text-align: left">Multi-gen LRU. Active/Inactive 목록으로 hot/cold 구분, <code class="language-plaintext highlighter-rouge">kswapd</code>가 백그라운드 스캔하며 cold &amp; dirty 우선 정리</td>
    </tr>
    <tr>
      <td style="text-align: center">Windows</td>
      <td style="text-align: left">Working-Set + Clock 아키텍처. 프로세스마다 WS 크기 자동 조절, 전역 밸런서가 과점유 시 회수</td>
    </tr>
    <tr>
      <td style="text-align: center">PintOS Project 3</td>
      <td style="text-align: left">Clock 알고리즘을 직접 구현. <code class="language-plaintext highlighter-rouge">struct frame</code> 리스트 + 핸드 포인터 유지, <code class="language-plaintext highlighter-rouge">pml4_is_accessed()</code>로 R 비트를 확인해 second-chance 부여</td>
    </tr>
  </tbody>
</table>

<h2 id="6-성능-분석-방법">6. 성능 분석 방법</h2>

<ol>
  <li><strong>Trace 재생</strong>: 메모리 참조 시퀀스를 돌려 폴트 카운트 비교</li>
  <li><strong>실험 변수</strong>: 프레임 수, Δ(working-set 윈도), R/Dirty 비트 리셋 주기</li>
  <li><strong>Thrashing 탐지</strong>: 폴트율 급증 + CPU 사용률↓ → 정책·resident set 튜닝 필요</li>
</ol>

<h2 id="7-요약">7. 요약</h2>

<ul>
  <li>Page Replacement Policy는 <strong>희생 페이지를 고르는 규칙</strong>이다</li>
  <li>이상적인 OPT는 불가능하므로, <strong>LRU 근사나 Clock 계열</strong>이 실용적이다</li>
  <li>정책마다 <strong>복잡도·메모리 오버헤드·성능·공정성</strong>의 trade-off가 있다</li>
  <li>실제 커널은 다단계 큐 + 참조/더티 비트로 LRU를 근사하고, 백그라운드 데몬(<code class="language-plaintext highlighter-rouge">kswapd</code> 등)으로 지속 튜닝한다</li>
  <li>PintOS 같은 교육용 OS에서는 <strong>Clock(Second-Chance)</strong> 구현이 가장 흔하며, R/Dirty 비트 처리·프레임 테이블 관리·swap I/O 동기화가 핵심이다</li>
</ul>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="cs" /><category term="운영체제" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Paging</title><link href="http://hwanlog.me/blog/cs/paging/" rel="alternate" type="text/html" title="Paging" /><published>2025-06-10T00:00:00+00:00</published><updated>2025-06-10T00:00:00+00:00</updated><id>http://hwanlog.me/blog/cs/paging</id><content type="html" xml:base="http://hwanlog.me/blog/cs/paging/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#페이징paging-기본-개념" id="markdown-toc-페이징paging-기본-개념">페이징(Paging) 기본 개념</a></li>
  <li><a href="#주소-변환translation-과정" id="markdown-toc-주소-변환translation-과정">주소 변환(Translation) 과정</a>    <ul>
      <li><a href="#cr3-레지스터-아직-이해-못함" id="markdown-toc-cr3-레지스터-아직-이해-못함">CR3 레지스터 (아직 이해 못함)</a>        <ul>
          <li><a href="#cr3의-역할-아직-이해-못함" id="markdown-toc-cr3의-역할-아직-이해-못함">CR3의 역할 (아직 이해 못함)</a></li>
        </ul>
      </li>
      <li><a href="#pte의-r-w--u-s--p-비트" id="markdown-toc-pte의-r-w--u-s--p-비트">PTE의 R-W / U-S / P 비트</a>        <ul>
          <li><a href="#cplcurrent-privilege-level" id="markdown-toc-cplcurrent-privilege-level">CPL(Current Privilege Level)</a></li>
        </ul>
      </li>
      <li><a href="#tlb-히트란" id="markdown-toc-tlb-히트란">TLB 히트란?</a>        <ul>
          <li><a href="#tlb-히트-깊게" id="markdown-toc-tlb-히트-깊게">TLB 히트 깊게</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a href="#운영체제의-역할" id="markdown-toc-운영체제의-역할">운영체제의 역할</a>    <ul>
      <li><a href="#tlb-flush" id="markdown-toc-tlb-flush">TLB Flush</a></li>
    </ul>
  </li>
  <li><a href="#페이지-교체page-replacement" id="markdown-toc-페이지-교체page-replacement">페이지 교체(Page Replacement)</a></li>
  <li><a href="#pintos-관점-요약" id="markdown-toc-pintos-관점-요약">PintOS 관점 요약</a></li>
  <li><a href="#다단계-페이징을-쓰는-이유" id="markdown-toc-다단계-페이징을-쓰는-이유">다단계 페이징을 쓰는 이유</a></li>
  <li><a href="#페이지-크기와-내부-단편화" id="markdown-toc-페이지-크기와-내부-단편화">페이지 크기와 내부 단편화</a></li>
  <li><a href="#정리" id="markdown-toc-정리">정리</a></li>
</ul>

<h2 id="페이징paging-기본-개념">페이징(Paging) 기본 개념</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">용어</th>
      <th style="text-align: center">설명</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">페이지(Page)</td>
      <td style="text-align: center">OS가 관리 단위로 삼는 고정 크기(대게 4Kb)의 가상 메모리 블록</td>
    </tr>
    <tr>
      <td style="text-align: center">프레임(Frame)</td>
      <td style="text-align: center">물리 메모리에서 페이지와 1 : 1로 매핑되는 동일 크기의 블록</td>
    </tr>
    <tr>
      <td style="text-align: center">페이지 테이블(Page Table)</td>
      <td style="text-align: center">“가상 페이지 번호 → 물리 프레임 번호 + 접근 권한”을 저장하는 자료구조</td>
    </tr>
    <tr>
      <td style="text-align: center">TLB(Translation Look-aside Buffer)</td>
      <td style="text-align: center">MMU 내부의 작은 캐시. 최근 주소 변환 결과를 보유해 속도를 높임</td>
    </tr>
  </tbody>
</table>

<p>페이징은 <strong>“가상 주소 ↔ 물리 주소”</strong> 사이에 간접층을 삽입해 각 프로세스가 <strong>독립적인 주소 공간</strong>을 갖도록 만드는 기술이다. 이를 통해 ① 보호(Protection), ② 공유(Sharing), ③ 공간 활용(세그먼트 단편화 제거)이라는 세 가지 핵심 목표를 달성한다.</p>

<h2 id="주소-변환translation-과정">주소 변환(Translation) 과정</h2>

<ol>
  <li>
    <p>가상 주소(48 bit) : 상위 9 bit씩 네 번 잘라 PML4→PDPT→PD→PT→오프센 순으로 인덱싱(x86-64 4-level 페이징 구조)</p>
  </li>
  <li>
    <p><strong>MMU</strong>가 CR3 레지스터에 있는 PML4 물리 주소를 읽어 다단계 테이블을 탐색</p>
  </li>
  <li>
    <p>최종 PTE(Page Table Entry, PT에 존재)에서 <strong>PFN(프레임 번호)</strong>와 <strong>R/W(read only/writable), U/S(user/supervisor), P(present/not-present)</strong> 비트를 읽어</p>

    <ul>
      <li>
        <p>접근 허용이면 <strong>물리 주소 = PFN x 4kb + 오프셋</strong></p>
      </li>
      <li>
        <p>접근 위반 x P비트 = 0이면 <strong>Page Fault</strong>발생 → OS 개입</p>
      </li>
    </ul>
  </li>
</ol>

<blockquote>
  <p><strong>TLB</strong>가 히트하면 1 ~ 3 단계가 생략되어 수십 ns 이내로 끝납니다.</p>
</blockquote>

<h3 id="cr3-레지스터-아직-이해-못함">CR3 레지스터 (아직 이해 못함)</h3>

<ul>
  <li>
    <p>x86-64 Control Register 3</p>

    <ul>
      <li>
        <p>상위 52비트 : 현재 주소 공간의 <strong>PML4 물리 주소</strong></p>
      </li>
      <li>
        <p>하위 12비트 : PCID(프로세스-TLB 태그) 및 플래그로써 컨텍스트 스위칭 때 CR3를 바꾸면 MMU가 “새 주소 공간으로 바뀌었다”고 간주하며, 대부분의 TLB 엔트리가 자동으로 무효화됨</p>
      </li>
    </ul>
  </li>
</ul>

<table>
  <thead>
    <tr>
      <th style="text-align: center">비트 범위</th>
      <th style="text-align: center">이름</th>
      <th style="text-align: center">내용</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">63-52</td>
      <td style="text-align: center">Reserved</td>
      <td style="text-align: center">(CPU 모델별 확장)</td>
    </tr>
    <tr>
      <td style="text-align: center"><strong>51-12</strong></td>
      <td style="text-align: center"><strong>PML4 물리베이스</strong></td>
      <td style="text-align: center">4KB 정렬된 주소(최상위 테이블)</td>
    </tr>
    <tr>
      <td style="text-align: center">11</td>
      <td style="text-align: center">PCID-Enable(인텔)</td>
      <td style="text-align: center">1 → PCID 지원 &amp; PCID = 0 이면 “글로벌 flush”</td>
    </tr>
    <tr>
      <td style="text-align: center">11-0</td>
      <td style="text-align: center"><strong>PCID</strong></td>
      <td style="text-align: center">Process-Context ID(0~4095)<br />TLB 태그로 붙어 “다른 PCID의 엔트리”는 그래도 남김</td>
    </tr>
  </tbody>
</table>

<h4 id="cr3의-역할-아직-이해-못함">CR3의 역할 (아직 이해 못함)</h4>

<ol>
  <li>
    <p>주소 공간 식별자</p>

    <ul>
      <li>
        <p>커널이 컨텍스트 스위칭 시 <code class="language-plaintext highlighter-rouge">mov %cr3, %rax / mov %rax, %cr3</code>로 새 값 로드</p>
      </li>
      <li>
        <p>PCID ≠ 이전 값이면, TLB 엔트리가 ‘다른 주소 공간’으로 구분되어 대부분 유지 → <strong>TLB flush 비용 감소</strong></p>
      </li>
    </ul>
  </li>
  <li>
    <p>전역(Global) 페이지</p>

    <ul>
      <li>PTE에 <strong>G 비트</strong>를 1로 두면 CR3 변경에도 flush되지 않음 (커널 코드/데이터용)</li>
    </ul>
  </li>
  <li>
    <p>Selective flush</p>

    <ul>
      <li>
        <p>특정 페이지만 무효화할 때 <code class="language-plaintext highlighter-rouge">invlpg (addr)</code>사용 → 해당 VPN + PCID 매칭 엔트리만 제거</p>
      </li>
      <li>
        <p>SMP 환경에서 다른 코어도 동일 주소 공간이면, 스스로도 같은 명령을 실행해야 함(IPI 브로드캐스트)</p>
      </li>
    </ul>
  </li>
</ol>

<p>PintOS처럼 PCID를 쓰지 않는 단순 구현도, CR3 재로드로 “전체 TLB flush” 효과를 얻음</p>

<h3 id="pte의-r-w--u-s--p-비트">PTE의 R-W / U-S / P 비트</h3>

<table>
  <thead>
    <tr>
      <th style="text-align: center">비트</th>
      <th style="text-align: center">이름</th>
      <th style="text-align: center">값이 1일 때 의미</th>
      <th style="text-align: center">값이 0일 때 의미</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">R/W (Read/Write)</td>
      <td style="text-align: center">쓰기 권한</td>
      <td style="text-align: center">읽기 + 쓰기 모두 허용</td>
      <td style="text-align: center">읽기 전용. 사용자/커널이 write 하면 PF_W = 1 폴트</td>
    </tr>
    <tr>
      <td style="text-align: center">U/S (User/Supervisor)</td>
      <td style="text-align: center">특권 등급</td>
      <td style="text-align: center">CPL 3(유저)에서도 접근 가능</td>
      <td style="text-align: center">CPL 0-2(커널)만 접근 가능 → 사용자 접근 시 PF_U = 1 폴트</td>
    </tr>
    <tr>
      <td style="text-align: center">P (Present)</td>
      <td style="text-align: center">존재 여부</td>
      <td style="text-align: center">해당 가상 페이지가 현재 물리 프레임에 매핑됨 → 정상 접근</td>
      <td style="text-align: center">“없음”으로 표시 → 접근 시 페이지 폴트 발생</td>
    </tr>
  </tbody>
</table>

<h4 id="cplcurrent-privilege-level">CPL(Current Privilege Level)</h4>

<table>
  <thead>
    <tr>
      <th style="text-align: center">링(Ring)/CPL 값</th>
      <th style="text-align: center">용도</th>
      <th style="text-align: center">사용자 코드에서 진입 가능?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">0</td>
      <td style="text-align: center">커널·하이퍼바이저·펌웨어처럼 시스템의 최상위 권한</td>
      <td style="text-align: center">✗</td>
    </tr>
    <tr>
      <td style="text-align: center">1</td>
      <td style="text-align: center">일부 마이크로커널·드라이버(거의 사용 X)</td>
      <td style="text-align: center">✗</td>
    </tr>
    <tr>
      <td style="text-align: center">2</td>
      <td style="text-align: center">‘서비스 OS’(Windows NT 초기) 등 특수 계층(거의 사용 X)</td>
      <td style="text-align: center">✗</td>
    </tr>
    <tr>
      <td style="text-align: center">3</td>
      <td style="text-align: center">일반 사용자 애플리케이션</td>
      <td style="text-align: center">✓</td>
    </tr>
  </tbody>
</table>

<ul>
  <li>
    <p><strong>CPL</strong>은 현재 실행 중인 명령어의 권한 레벨이다.</p>
  </li>
  <li>
    <p>CPU 레지스터에 따로 존재하지 않고 <strong>CS 세그먼트 하위 2비트</strong>가 CPL로 해석됨</p>
  </li>
  <li>
    <p>페이징 권한 검사 :</p>

    <ul>
      <li>
        <p>페이지 엔트리 <strong>U/S 비트</strong>가 0이면 “Ring 0-2만, 즉 CPL 0~2만 접근 가능”</p>
      </li>
      <li>
        <p><strong>R/W 비트</strong>가 0이면, “읽기만 가능, 쓰기는 CPL에 관계없이 금지”</p>
      </li>
    </ul>
  </li>
  <li>
    <p>시스템 콜(예 : <code class="language-plaintext highlighter-rouge">syscall</code>, <code class="language-plaintext highlighter-rouge">int 0x80</code>)은 게이트를 통해 Ring 3→Ring 0으로 ‘권한 상승’한 뒤, 커널이 <code class="language-plaintext highlighter-rouge">iretq</code>로 돌아올 때 Ring 3로 복귀한다.</p>
  </li>
</ul>

<h3 id="tlb-히트란">TLB 히트란?</h3>

<p>CPU가 가상주소를 던졌을 때 <strong>TLB(주소 변환 캐시)</strong> 안에 그 VA→PA 매핑이 이미 들어 있으면 <strong>히트(hit)</strong>라고 부릅니다. 이 경우 MMU가 페이지 테이블을 전혀 걷지 않아도 되므로 변환이 한두 사이클 안에 끝납니다. 반대로 없으면 <strong>미스(miss)</strong> → 긴 ‘4-단계 페이지 테이블 워크’가 수행됩니다.</p>

<h4 id="tlb-히트-깊게">TLB 히트 깊게</h4>

<table>
  <thead>
    <tr>
      <th style="text-align: center">레벨</th>
      <th style="text-align: center">커버 범위</th>
      <th style="text-align: center">페이지 크기</th>
      <th style="text-align: center">방식</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">L1-DTLB</td>
      <td style="text-align: center">데이터 변환 전용</td>
      <td style="text-align: center">4KB / 2MB</td>
      <td style="text-align: center">64 엔트리, 4-way set-assoc</td>
    </tr>
    <tr>
      <td style="text-align: center">L1-ITLB</td>
      <td style="text-align: center">코드 변환 전용</td>
      <td style="text-align: center">4KB / 2MB</td>
      <td style="text-align: center">128 엔트리, 4-way</td>
    </tr>
    <tr>
      <td style="text-align: center">STLB(L2)</td>
      <td style="text-align: center">Unified</td>
      <td style="text-align: center">4KB / 2MB / 1GB</td>
      <td style="text-align: center">1536 엔트리 이상</td>
    </tr>
  </tbody>
</table>

<ul>
  <li>
    <p><strong>히트(Hit)</strong> → “요청한 가상주소의 상위 n비트(=VPN)가 TLB태그에 이미 존재하여, 물리 프레임 번호(PFN)를 즉시 반환할 수 있었다”는 뜻</p>
  </li>
  <li>
    <p><strong>미스(miss)</strong> → MMU가 <strong>다단계 페이지 테이블 워크</strong>를 수행하면서 메모리를 실제로 읽어야 하므로 수십~수백 ns 추가 지연이 발생</p>
  </li>
  <li>
    <p>멀티코어에서의 일관성 : 같은 물리 페이지를 서로 다른 CPU가 매핑 바꿀 수 있으므로, PTE가 변하면 <strong>IPI(Inter-Processor Interrupt)</strong>로 다른 코어에 “TLB flush 요청”을 보내 반드시 무효화하게 한다.</p>
  </li>
</ul>

<blockquote>
  <p>체감적으로 L1 TLB 히트는 ≒ 1-3 cycle, STLB 히트는 ≒ 5-10 cycle, 미스는 수십 cycle이기 때문에 “TLB 친화적인(=순차·지역성 높은) 메모리 접근”이 성능에 큰 영향을 줍니다.</p>
</blockquote>

<h2 id="운영체제의-역할">운영체제의 역할</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">시점</th>
      <th style="text-align: left">OS가 수행하는 일</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">프로세스 생성</td>
      <td style="text-align: left">새 페이지 테이블 구성, 코드/데이터 영역 PTE를 “not-present”로 표기</td>
    </tr>
    <tr>
      <td style="text-align: center">페이지 폴트</td>
      <td style="text-align: left">ⓐ 유효 but 매핑 없음 → <strong>Demand Paging</strong><br /> - 여유 프레임 할당<br /> - 디스크에서 해당 페이지 로드<br /> - PTE 업데이트, 다시 실행<br /> ⓑ 스택 자동 확장 조건 위배, 보호 위반 → <strong>Segmentation Fault</strong></td>
    </tr>
    <tr>
      <td style="text-align: center">메모리 부족</td>
      <td style="text-align: left"><strong>페이지 교체 알고리즘</strong>으로 Victim 선정, → 디스크 스왑 아웃 → PTE 수정</td>
    </tr>
    <tr>
      <td style="text-align: center">컨텍스트 스위칭</td>
      <td style="text-align: left">CR3에 새 프로세스 PML4 물리 주소 기록, TLB flush</td>
    </tr>
  </tbody>
</table>

<h3 id="tlb-flush">TLB Flush</h3>

<p>“페이지 테이블을 고쳤으니 캐시에 남은 옛 변환을 버려라”는 명령입니다.</p>

<p>대표 방법 :</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">mov %cr3, %rax / mov %rax, %cr3</code> - CR3를 재로드 해 전체(비-Global) TLB 무효화</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">invlpg (addr)</code> - 지정 페이지 하나만 정밀 무효화</p>
  </li>
</ul>

<p>둘 다 커널 모드에서만 가능하며, SMP 환경에선 다른 CPU에도 IPI로 flush를 전파해야 함</p>

<h2 id="페이지-교체page-replacement">페이지 교체(Page Replacement)</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">알고리즘</th>
      <th style="text-align: center">개요</th>
      <th style="text-align: center">장단점</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">Optimal(OPT)</td>
      <td style="text-align: center">“앞으로 가장 늦게 재참조될 페이지” 제거</td>
      <td style="text-align: center">이론적 최적 · 실현 불가</td>
    </tr>
    <tr>
      <td style="text-align: center">LRU</td>
      <td style="text-align: center">최근에 가장 오래 안 쓴 페이지 선택</td>
      <td style="text-align: center">좋은 hit 을, 구현 비용 높음</td>
    </tr>
    <tr>
      <td style="text-align: center">Clock(2nd-chance)</td>
      <td style="text-align: center">원형 큐 + reference bit로 LRU 근사</td>
      <td style="text-align: center">구현 간단, 성능 무난</td>
    </tr>
  </tbody>
</table>

<p>기존에 올렸던 PintOS Project3에서는 Clock 변형으로 구현하였다.</p>

<h2 id="pintos-관점-요약">PintOS 관점 요약</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">구조체/함수</th>
      <th style="text-align: left">하는 일</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center"><code class="language-plaintext highlighter-rouge">struct page</code></td>
      <td style="text-align: left">한 가상 페이지의 메타데이터(SPT key), 타입(anon/file), 프레임, dirty등</td>
    </tr>
    <tr>
      <td style="text-align: center">Supplemental Page Table(SPT)</td>
      <td style="text-align: left">프로세스별 해시 맵/트리. <code class="language-plaintext highlighter-rouge">spt_find_page()</code>, <code class="language-plaintext highlighter-rouge">spt_insert_page()</code></td>
    </tr>
    <tr>
      <td style="text-align: center"><code class="language-plaintext highlighter-rouge">vm_try_handle_fault()</code></td>
      <td style="text-align: left">페이지 폴트 핸들러 진입 지접. 스택 성장 ‧ lazy loading 로직 포함</td>
    </tr>
    <tr>
      <td style="text-align: center"><code class="language-plaintext highlighter-rouge">swap_in/out()</code></td>
      <td style="text-align: left">스왑 디스크 I/O 실행. Clock Victim이 anon이면 out, fault시 in</td>
    </tr>
    <tr>
      <td style="text-align: center"><code class="language-plaintext highlighter-rouge">file_backed_initializer()</code></td>
      <td style="text-align: left">mmap · lazy file load에 사용될 custom swap_in/out 등록</td>
    </tr>
  </tbody>
</table>

<h2 id="다단계-페이징을-쓰는-이유">다단계 페이징을 쓰는 이유</h2>

<ol>
  <li>
    <p><strong>공간 절약</strong> - 4KB(2<sup>12</sup>) 페이지 x 2<sup>20</sup> → 4GB 주소 공간. 다단계(4-level)면 “사용된 테이블만” 할당</p>
  </li>
  <li>
    <p><strong>보호</strong> - 각 레벨 테이블을 4KB 페이지로 두고 U/S 비트 = 0으로 하면 <strong>커널이 관리</strong></p>
  </li>
  <li>
    <p><strong>공유</strong> - 부모-자식 fork시 상위 N개 테이블을 <strong>copy-on-write</strong> 방식으로 공유 가능(메모리 절약)</p>
  </li>
</ol>

<h2 id="페이지-크기와-내부-단편화">페이지 크기와 내부 단편화</h2>

<ul>
  <li>
    <p>페이지 크기가 크면 → TLB miss 감소(+), 내부 단편화(-), I/O 효율(+)</p>
  </li>
  <li>
    <p>현대 x86-64는 <strong>4KB 기본 + 2MB/1GB Huge Page 옵션</strong> 제공</p>
  </li>
</ul>

<h2 id="정리">정리</h2>

<p>페이징은 <strong>프로세스마다 독립적/선형적인 주소 공간</strong>을 제공하면서, <strong>OS가 필요한 때만 물리 메모리/디스크를 할당</strong>하고 <strong>TLB/다단계 페이지 테이블</strong>로 성능과 메모리 사용량을 균형있게 최적화하는 메커니즘입니다. PintOS 프로젝트에서 구현·조정하는 모든 VM 기능들은 이 큰 틀 안에 위치합니다.</p>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="cs" /><category term="운영체제" /><summary type="html"><![CDATA[OS가 가상 메모리를 어떻게 관리할까?]]></summary></entry><entry><title type="html">Swap Disk</title><link href="http://hwanlog.me/blog/cs/swap-disk/" rel="alternate" type="text/html" title="Swap Disk" /><published>2025-06-10T00:00:00+00:00</published><updated>2025-06-10T00:00:00+00:00</updated><id>http://hwanlog.me/blog/cs/swap-disk</id><content type="html" xml:base="http://hwanlog.me/blog/cs/swap-disk/"><![CDATA[<ul class="large-only" id="markdown-toc">
  <li><a href="#스왑-디스크swap-disk의-기본-개념" id="markdown-toc-스왑-디스크swap-disk의-기본-개념">스왑 디스크(Swap Disk)의 기본 개념</a></li>
  <li><a href="#동작-흐름" id="markdown-toc-동작-흐름">동작 흐름</a></li>
</ul>

<h2 id="스왑-디스크swap-disk의-기본-개념">스왑 디스크(Swap Disk)의 기본 개념</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: center">개념</th>
      <th style="text-align: left">설명</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">목적</td>
      <td style="text-align: left">물리 메모리(RAM)가 부족할 때, 사용하지 않는 페이지(4KB 단위)를 SSD/HDD같은 보조 저장장치에 임시로 저장해 두는 공간</td>
    </tr>
    <tr>
      <td style="text-align: center">형태</td>
      <td style="text-align: left">① 스왑 파티션 (독립된 블록 디바이스)<br />② 스왑 파일 (일반 파일시스템 위 파일)</td>
    </tr>
    <tr>
      <td style="text-align: center">구분</td>
      <td style="text-align: left">페이지가 RAM에 있으면 present 상태, 스왑으로 나가면 swapped 상태(PTE의 present 비트 = 0), 나머지 비트로 스왑 슬롯 번호 등 메타데이터 저장</td>
    </tr>
    <tr>
      <td style="text-align: center">근거</td>
      <td style="text-align: left">가상메모리 구현에서 페이지 부재(page fault)시 디스크 I/O(DMA)로 교체</td>
    </tr>
  </tbody>
</table>

<h2 id="동작-흐름">동작 흐름</h2>

<ol>
  <li>
    <p>Page Fault</p>

    <ul>
      <li>CPU가 PTE의 present 비트를 확인 → 0이면 트랩 → 커널의 <strong>page-fault 핸들러</strong> 진입</li>
    </ul>
  </li>
  <li>
    <p>물리 프레임 할당 실패</p>

    <ul>
      <li>모든 프레임이 사용 중이면 <strong>페이지 교체</strong>(page replacement) 정책(LRU/Clock 등)으로 희생 페이지 선정</li>
    </ul>
  </li>
  <li>
    <p>swap-out</p>

    <ol>
      <li>
        <p>스왑 비트맵(bitmap)에서 빈 슬롯 검색</p>
      </li>
      <li>
        <p>페이지 내용을 8 섹터(512B x 8 = 4KB)단위로 <code class="language-plaintext highlighter-rouge">block_write()</code></p>
      </li>
      <li>
        <p>PTE present = 0, swapped flag · 슬롯 번호 기록</p>
      </li>
    </ol>
  </li>
  <li>
    <p>swap-in(해당 가상주소 재접근 시)</p>

    <ol>
      <li>
        <p>새 프레임 확보 후 <code class="language-plaintext highlighter-rouge">block_read()</code>로 8섹터 읽음</p>
      </li>
      <li>
        <p>PTE present = 1, 스왑 메타데이터 초기화, TLB flush</p>
      </li>
      <li>
        <p>비트맵 슬롯 free</p>
      </li>
    </ol>
  </li>
  <li>
    <p>I/O 세부</p>

    <ul>
      <li>실제 전송은 디스크 컨트롤러가 DMA로 처리 → 완료 시 인터럽트 발생 → 커널이 잠들어 있던 프로세스 깨움</li>
    </ul>
  </li>
</ol>]]></content><author><name>JeongHwan Yun</name><email>jh327373@gmail.com</email></author><category term="blog" /><category term="cs" /><category term="운영체제" /><summary type="html"><![CDATA[Anonymous Page를 구현하기 위한 필수 개념 Swap Disk에 대해 알아보자]]></summary></entry></feed>