<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Digital Agora</title>
    <link>https://digitalagora.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 28 Jun 2026 05:51:09 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>solitude12</managingEditor>
    <item>
      <title>[CS] OSI 7계층</title>
      <link>https://digitalagora.tistory.com/112</link>
      <description>&lt;p data-end=&quot;348&quot; data-start=&quot;300&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;네트워크 통신의 가장 기본 구조를 이해하려면 반드시 알아야 하는 표준 프레임워크&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;500&quot; data-start=&quot;350&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터 네트워크 통신은 단순히 데이터를 보내고 받는 동작이 아니라 여러 단계의 프로세스로 이루어집니다.&lt;br /&gt;이 과정을 &lt;b&gt;명확하게 분리하고 설명하기 위해 만든 이론적 기준이 바로 OSI 7계층입니다.&lt;/b&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-end=&quot;647&quot; data-start=&quot;502&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;647&quot; data-start=&quot;504&quot; data-ke-size=&quot;size16&quot;&gt;OSI 모델은 국제표준화기구(ISO)에서 제안한 **참조 모델(reference model)**로서,&lt;br /&gt;네트워크 통신을 7단계로 나누어 기능별로 설명할 수 있도록 설계되었습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;652&quot; data-start=&quot;649&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;673&quot; data-start=&quot;654&quot; data-ke-size=&quot;size26&quot;&gt;  OSI 7계층 전체 개요&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767590298423&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;┌─────────────────────────────────┐
│ 7. Application (응용 계층)      │    사용자와 직접 상호작용
├─────────────────────────────────┤
│ 6. Presentation (표현 계층)     │    데이터 형식 변환 및 암호화
├─────────────────────────────────┤
│ 5. Session (세션 계층)          │    통신 세션 및 상태 관리
├─────────────────────────────────┤
│ 4. Transport (전송 계층)        │    신뢰성/흐름 제어
├─────────────────────────────────┤
│ 3. Network (네트워크 계층)      │    경로 선택(라우팅)
├─────────────────────────────────┤
│ 2. Data Link (데이터 링크 계층) │    프레임 단위 전송/오류 제어
├─────────────────────────────────┤
│ 1. Physical (물리 계층)         │    비트(bit) 수준의 전송
└─────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1317&quot; data-start=&quot;1314&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1340&quot; data-start=&quot;1319&quot; data-ke-size=&quot;size26&quot;&gt;  OSI 모델이 왜 중요한가?&lt;/h2&gt;
&lt;p data-end=&quot;1503&quot; data-start=&quot;1342&quot; data-ke-size=&quot;size16&quot;&gt;✔ 네트워크 통신을 &lt;b&gt;단계별로 시각화&lt;/b&gt;할 수 있게 해줍니다.&lt;br /&gt;✔ 통신 과정에서 &lt;b&gt;어떤 단계에서 문제가 있는지 빠르게 파악&lt;/b&gt;할 수 있습니다.&lt;br /&gt;✔ 복잡한 기술들을 &lt;b&gt;하위 기능으로 분리&lt;/b&gt;해 이해할 수 있습니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-end=&quot;1609&quot; data-start=&quot;1505&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;1609&quot; data-start=&quot;1507&quot; data-ke-size=&quot;size16&quot;&gt;현실의 인터넷은 TCP/IP 모델을 기반으로 하지만, OSI 모델은 학습과 구조적 이해에서 표준으로 쓰입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;1614&quot; data-start=&quot;1611&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1637&quot; data-start=&quot;1616&quot; data-ke-size=&quot;size26&quot;&gt;  각 계층의 역할과 핵심 기능&lt;/h2&gt;
&lt;hr data-end=&quot;1642&quot; data-start=&quot;1639&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1679&quot; data-start=&quot;1644&quot; data-ke-size=&quot;size23&quot;&gt;  1계층 &amp;bull; Physical Layer (물리 계층)&lt;/h3&gt;
&lt;p data-end=&quot;1725&quot; data-start=&quot;1681&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;핵심 역할&lt;/b&gt;: 전기적/광 신호로 &lt;b&gt;0과 1의 비트&lt;/b&gt;를 전송합니다.&lt;/p&gt;
&lt;p data-end=&quot;1742&quot; data-start=&quot;1727&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;무엇을 하는가?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1807&quot; data-start=&quot;1744&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1761&quot; data-start=&quot;1744&quot;&gt;비트 단위로 신호를 전송&lt;/li&gt;
&lt;li data-end=&quot;1788&quot; data-start=&quot;1762&quot;&gt;전송 매체(케이블, 광섬유, 무선) 정의&lt;/li&gt;
&lt;li data-end=&quot;1807&quot; data-start=&quot;1789&quot;&gt;신호 속도, 전압, 커넥터 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1821&quot; data-start=&quot;1809&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;예시 장비&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1845&quot; data-start=&quot;1822&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1845&quot; data-start=&quot;1822&quot;&gt;랜 케이블, 허브(Hub), 리피터 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1931&quot; data-start=&quot;1847&quot; data-ke-size=&quot;size16&quot;&gt;  이 계층은 &lt;b&gt;데이터의 내용에 관심이 없고&lt;/b&gt;, 오직 물리적 전송에 집중합니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1936&quot; data-start=&quot;1933&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1978&quot; data-start=&quot;1938&quot; data-ke-size=&quot;size23&quot;&gt;  2계층 &amp;bull; Data Link Layer (데이터 링크 계층)&lt;/h3&gt;
&lt;p data-end=&quot;1525&quot; data-start=&quot;1514&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1587&quot; data-start=&quot;1526&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1564&quot; data-start=&quot;1526&quot;&gt;물리 계층에서 전달된 데이터를 &lt;b&gt;프레임 단위로 묶어 전송&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1587&quot; data-start=&quot;1565&quot;&gt;같은 네트워크(LAN) 내 통신 담당&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1608&quot; data-start=&quot;1589&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;대표 프로토콜 / 기술&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1639&quot; data-start=&quot;1609&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1619&quot; data-start=&quot;1609&quot;&gt;Ethernet&lt;/li&gt;
&lt;li data-end=&quot;1625&quot; data-start=&quot;1620&quot;&gt;ARP&lt;/li&gt;
&lt;li data-end=&quot;1639&quot; data-start=&quot;1626&quot;&gt;MAC Address&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1653&quot; data-start=&quot;1641&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;대표 장비&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1671&quot; data-start=&quot;1654&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1662&quot; data-start=&quot;1654&quot;&gt;Switch&lt;/li&gt;
&lt;li data-end=&quot;1671&quot; data-start=&quot;1663&quot;&gt;Bridge&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1691&quot; data-start=&quot;1673&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;이미지로 이해하기&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-end=&quot;1730&quot; data-start=&quot;1692&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;1730&quot; data-start=&quot;1694&quot; data-ke-size=&quot;size16&quot;&gt;같은 건물 안에서 **호수(MAC 주소)**만 보고 배달하는 택배&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-end=&quot;2238&quot; data-start=&quot;2235&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2276&quot; data-start=&quot;2240&quot; data-ke-size=&quot;size23&quot;&gt;  3계층 &amp;bull; Network Layer (네트워크 계층)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1836&quot; data-start=&quot;1787&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1810&quot; data-start=&quot;1787&quot;&gt;서로 다른 네트워크 간 데이터 전달&lt;/li&gt;
&lt;li data-end=&quot;1836&quot; data-start=&quot;1811&quot;&gt;목적지까지 &lt;b&gt;경로 선택(라우팅)&lt;/b&gt; 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;대표 프로토콜&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1878&quot; data-start=&quot;1853&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1871&quot; data-start=&quot;1853&quot;&gt;IP (IPv4 / IPv6)&lt;/li&gt;
&lt;li data-end=&quot;1878&quot; data-start=&quot;1872&quot;&gt;ICMP&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;대표 장비&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1901&quot; data-start=&quot;1893&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1901&quot; data-start=&quot;1893&quot;&gt;Router&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2469&quot; data-start=&quot;2390&quot; data-ke-size=&quot;size16&quot;&gt;  이 계층은 &lt;b&gt;데이터가 목적지까지 어떻게 가야 하는지&lt;/b&gt;를 결정합니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2474&quot; data-start=&quot;2471&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2512&quot; data-start=&quot;2476&quot; data-ke-size=&quot;size23&quot;&gt;  4계층 &amp;bull; Transport Layer (전송 계층)&lt;/h3&gt;
&lt;p data-end=&quot;2025&quot; data-start=&quot;2014&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2081&quot; data-start=&quot;2026&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2058&quot; data-start=&quot;2026&quot;&gt;송신자와 수신자 간 &lt;b&gt;신뢰성 있는 데이터 전달&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2081&quot; data-start=&quot;2059&quot;&gt;포트 번호를 이용해 애플리케이션 구분&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2560&quot; data-start=&quot;2551&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;기능&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2599&quot; data-start=&quot;2561&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2570&quot; data-start=&quot;2561&quot;&gt;흐름 제어&lt;/li&gt;
&lt;li data-end=&quot;2580&quot; data-start=&quot;2571&quot;&gt;오류 제어&lt;/li&gt;
&lt;li data-end=&quot;2599&quot; data-start=&quot;2581&quot;&gt;포트 번호를 이용한 연결 구분&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2097&quot; data-start=&quot;2083&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;대표 프로토콜&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2109&quot; data-start=&quot;2098&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2103&quot; data-start=&quot;2098&quot;&gt;TCP&lt;/li&gt;
&lt;li data-end=&quot;2109&quot; data-start=&quot;2104&quot;&gt;UDP&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2128&quot; data-start=&quot;2111&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;TCP vs UDP&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2184&quot; data-start=&quot;2129&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2155&quot; data-start=&quot;2129&quot;&gt;TCP: 신뢰성, 순서 보장 (웹, 이메일)&lt;/li&gt;
&lt;li data-end=&quot;2184&quot; data-start=&quot;2156&quot;&gt;UDP: 빠른 속도, 비연결 (스트리밍, 게임)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-end=&quot;2778&quot; data-start=&quot;2698&quot; data-ke-size=&quot;size16&quot;&gt;  응용 계층에서 요청한 데이터를 &lt;b&gt;신뢰성 있게 송수신&lt;/b&gt;하는 역할입니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2783&quot; data-start=&quot;2780&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2819&quot; data-start=&quot;2785&quot; data-ke-size=&quot;size23&quot;&gt;  5계층 &amp;bull; Session Layer (세션 계층)&lt;/h3&gt;
&lt;p data-end=&quot;2297&quot; data-start=&quot;2286&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2337&quot; data-start=&quot;2298&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2326&quot; data-start=&quot;2298&quot;&gt;통신 &lt;b&gt;세션의 생성, 유지, 종료&lt;/b&gt; 관리&lt;/li&gt;
&lt;li data-end=&quot;2337&quot; data-start=&quot;2327&quot;&gt;연결 상태 제어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2351&quot; data-start=&quot;2339&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;대표 기술&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2375&quot; data-start=&quot;2352&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2369&quot; data-start=&quot;2352&quot;&gt;NetBIOS Session&lt;/li&gt;
&lt;li data-end=&quot;2375&quot; data-start=&quot;2370&quot;&gt;RPC&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2395&quot; data-start=&quot;2377&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;이미지로 이해하기&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-end=&quot;2432&quot; data-start=&quot;2396&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;p data-end=&quot;2432&quot; data-start=&quot;2398&quot; data-ke-size=&quot;size16&quot;&gt;전화 통화의 &amp;ldquo;연결됨 / 통화 중 / 끊김&amp;rdquo; 상태 관리&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;2466&quot; data-start=&quot;2434&quot; data-ke-size=&quot;size16&quot;&gt;  실무에서는 다른 계층과 통합되는 경우가 많습니다.&lt;/p&gt;
&lt;hr data-end=&quot;3002&quot; data-start=&quot;2999&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3043&quot; data-start=&quot;3004&quot; data-ke-size=&quot;size23&quot;&gt;  6계층 &amp;bull; Presentation Layer (표현 계층)&lt;/h3&gt;
&lt;p data-end=&quot;2525&quot; data-start=&quot;2514&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2563&quot; data-start=&quot;2526&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2539&quot; data-start=&quot;2526&quot;&gt;데이터 형식 변환&lt;/li&gt;
&lt;li data-end=&quot;2553&quot; data-start=&quot;2540&quot;&gt;암호화 / 복호화&lt;/li&gt;
&lt;li data-end=&quot;2563&quot; data-start=&quot;2554&quot;&gt;압축 / 해제&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2577&quot; data-start=&quot;2565&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;대표 기술&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2608&quot; data-start=&quot;2578&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2589&quot; data-start=&quot;2578&quot;&gt;SSL / TLS&lt;/li&gt;
&lt;li data-end=&quot;2608&quot; data-start=&quot;2590&quot;&gt;문자 인코딩 (UTF-8 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2628&quot; data-start=&quot;2610&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;이미지로 이해하기&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-end=&quot;2667&quot; data-start=&quot;2629&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;2667&quot; data-start=&quot;2631&quot; data-ke-size=&quot;size16&quot;&gt;문서를 PDF로 변환하거나&lt;br /&gt;암호화된 데이터를 해독하는 과정&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;3239&quot; data-start=&quot;3236&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3279&quot; data-start=&quot;3241&quot; data-ke-size=&quot;size23&quot;&gt;  7계층 &amp;bull; Application Layer (응용 계층)&lt;/h3&gt;
&lt;p data-end=&quot;2725&quot; data-start=&quot;2714&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2752&quot; data-start=&quot;2726&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2752&quot; data-start=&quot;2726&quot;&gt;사용자가 직접 사용하는 네트워크 서비스 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2768&quot; data-start=&quot;2754&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;대표 프로토콜&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2802&quot; data-start=&quot;2769&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2783&quot; data-start=&quot;2769&quot;&gt;HTTP / HTTPS&lt;/li&gt;
&lt;li data-end=&quot;2789&quot; data-start=&quot;2784&quot;&gt;FTP&lt;/li&gt;
&lt;li data-end=&quot;2796&quot; data-start=&quot;2790&quot;&gt;SMTP&lt;/li&gt;
&lt;li data-end=&quot;2802&quot; data-start=&quot;2797&quot;&gt;DNS&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2822&quot; data-start=&quot;2804&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;이미지로 이해하기&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-end=&quot;2868&quot; data-start=&quot;2823&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;2868&quot; data-start=&quot;2825&quot; data-ke-size=&quot;size16&quot;&gt;웹 브라우저에서 URL을 입력하고&lt;br /&gt;서버로부터 화면을 받아보는 전체 과정&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;3472&quot; data-start=&quot;3469&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3493&quot; data-start=&quot;3474&quot; data-ke-size=&quot;size26&quot;&gt;⚖️ OSI 7계층 vs TCP/IP 모델&lt;/h2&gt;
&lt;p data-end=&quot;3611&quot; data-start=&quot;3495&quot; data-ke-size=&quot;size16&quot;&gt;OSI 7계층은 &lt;b&gt;학생/초보자 학습용&lt;/b&gt;으로 강력한 개념 도구입니다.&lt;br /&gt;반면 TCP/IP는 &lt;b&gt;실제 인터넷에서 사용되는 구조&lt;/b&gt;입니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;3744&quot; data-start=&quot;3613&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;3744&quot; data-start=&quot;3670&quot;&gt;
&lt;tr data-end=&quot;3698&quot; data-start=&quot;3670&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3675&quot; data-start=&quot;3670&quot;&gt;목적&lt;/td&gt;
&lt;td data-end=&quot;3684&quot; data-start=&quot;3675&quot; data-col-size=&quot;sm&quot;&gt;개념적 모델&lt;/td&gt;
&lt;td data-end=&quot;3698&quot; data-start=&quot;3684&quot; data-col-size=&quot;sm&quot;&gt;현실적 인터넷 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3719&quot; data-start=&quot;3699&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3706&quot; data-start=&quot;3699&quot;&gt;계층 수&lt;/td&gt;
&lt;td data-end=&quot;3711&quot; data-start=&quot;3706&quot; data-col-size=&quot;sm&quot;&gt;7개&lt;/td&gt;
&lt;td data-end=&quot;3719&quot; data-start=&quot;3711&quot; data-col-size=&quot;sm&quot;&gt;4~5개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3744&quot; data-start=&quot;3720&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3725&quot; data-start=&quot;3720&quot;&gt;활용&lt;/td&gt;
&lt;td data-end=&quot;3733&quot; data-start=&quot;3725&quot; data-col-size=&quot;sm&quot;&gt;설명/교육&lt;/td&gt;
&lt;td data-end=&quot;3744&quot; data-start=&quot;3733&quot; data-col-size=&quot;sm&quot;&gt;실제 네트워크&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3840&quot; data-start=&quot;3746&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, OSI의 세션&amp;middot;표현&amp;middot;응용 계층은 TCP/IP에서는 &lt;b&gt;응용 계층 하나로 통합&lt;/b&gt;됩니다.&lt;span data-state=&quot;closed&quot;&gt;&lt;span data-testid=&quot;webpage-citation-pill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3845&quot; data-start=&quot;3842&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3861&quot; data-start=&quot;3847&quot; data-ke-size=&quot;size26&quot;&gt;  면접 답변 예시&lt;/h2&gt;
&lt;p data-end=&quot;3890&quot; data-start=&quot;3863&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. OSI 7계층에 대해 설명해 주세요.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-end=&quot;4117&quot; data-start=&quot;3892&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;4117&quot; data-start=&quot;3894&quot; data-ke-size=&quot;size16&quot;&gt;OSI 7계층은 네트워크 통신 과정을 기능별로 7단계로 나누어 정의한 참조 모델입니다.&lt;br /&gt;실제 인터넷은 TCP/IP 모델을 기반으로 동작하지만, OSI 7계층은 통신 과정을 구조적으로 이해하고 설명하기 위해 사용됩니다.&lt;br /&gt;물리적인 신호 전송부터 사용자가 직접 사용하는 응용 서비스까지 각 계층의 역할이 명확히 분리되어 있어,&lt;br /&gt;네트워크 흐름을 단계적으로 파악하거나 장애 발생 시 원인을 계층 단위로 분석하는 데 유용합니다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Computer Science</category>
      <category>network</category>
      <category>OSI 7 계층</category>
      <category>네트워크</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/112</guid>
      <comments>https://digitalagora.tistory.com/112#entry112comment</comments>
      <pubDate>Mon, 5 Jan 2026 14:27:49 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Batch] Spring Batch 간단 정리</title>
      <link>https://digitalagora.tistory.com/111</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Spring Batch 기본 구성 요소&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Batch는 대규모 데이터 처리에 최적화된 프레임워크로 대량의 데이터를 처리하거나 활용하는데 널리 사용된다. 스프링 배치에서 사용되는 주된 구성 요소들을 큰 순서부터 차례로 나열하면 다음과 같다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Job&lt;/b&gt;: 하나 이상의 Step으로 구성된 배치 처리 단위&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Step&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 작업의 논리적 단위로, Tasklet이나 Chunk 기반 처리로 구현&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Tasklet&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 단순 반복 작업을 처리하기 위한 인터페이스&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Chunk&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 데이터를 일정 크기 단위로 나누어 처리하는 방식. 내부적으로는 크게 reader, processor, writer 형태로 처리.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;tasklet vs chunk&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.0542%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 41.7054%;&quot;&gt;chunk&lt;/td&gt;
&lt;td style=&quot;width: 46.2403%;&quot;&gt;tasklet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.0542%;&quot;&gt;장점&lt;/td&gt;
&lt;td style=&quot;width: 41.7054%;&quot;&gt;대량 데이터를 효율적으로 처리 가능(읽기, 처리, 쓰기)&lt;/td&gt;
&lt;td style=&quot;width: 46.2403%;&quot;&gt;간단한 반복 작업에 적합함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.0542%;&quot;&gt;사용 사례&lt;/td&gt;
&lt;td style=&quot;width: 41.7054%;&quot;&gt;파일 로드, DB 마이그레이션, ETL 작업&lt;/td&gt;
&lt;td style=&quot;width: 46.2403%;&quot;&gt;단일 작업, 외부 API 호출 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;코드 예시&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1734938613925&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableBatchProcessing
public class BatchConfig {

    @Bean
    public Job exampleJob(JobBuilderFactory jobBuilderFactory, Step exampleStep) {
        return jobBuilderFactory.get(&quot;exampleJob&quot;)
                .start(exampleStep)
                .build();
    }

    @Bean
    public Step exampleStep(StepBuilderFactory stepBuilderFactory) {
        return stepBuilderFactory.get(&quot;exampleStep&quot;)
                .&amp;lt;String, String&amp;gt;chunk(10)  // Chunk 단위 설정
                .reader(itemReader())
                .processor(itemProcessor())
                .writer(itemWriter())
                .build();
    }

    @Bean
    public ItemReader&amp;lt;String&amp;gt; itemReader() {
        return new SimpleItemReader();
    }

    @Bean
    public ItemProcessor&amp;lt;String, String&amp;gt; itemProcessor() {
        return new SimpleItemProcessor();
    }

    @Bean
    public ItemWriter&amp;lt;String&amp;gt; itemWriter() {
        return new SimpleItemWriter();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Spring Batch 성능 최적화 기법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 방법이 있겠지만 크게 4가지가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Multi-threaded Step
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;말 그대로 데이터를 병렬 처리해 성능을 향상시키는 방법.&lt;/li&gt;
&lt;li&gt;다만 멀티 쓰레드 시 가지는 문제점에 대해서 고민(병목 현상, 데이터 정합성 등)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Partitioning
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데이터를 파티션으로 나누어서 병렬 처리하는 방식&lt;/li&gt;
&lt;li&gt;멀티 쓰레드와 유사하지만 말 그대로 하나의 작업을 파트별로 나눠서 처리(1000가지가 있다면 100개씩)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Parallel Step
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;만약 하나의 Step에서 순서대로 처리하지 않아도 되는 작업이라면 별도로 그 작업을 별도로 병렬로 나눠서 처리하는 방식.&lt;/li&gt;
&lt;li&gt;Step의 흐름을 하나 더 나눠서 처리하는 방식.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Chunk 크기 조절
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Chunk 크기에 따른 데이터 크기와 메모리 사용량을 고려해 적절한 크기를 설정해 처리 효율을 극대화 하는 방식.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Scheduler를 활용한 통합&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Batch는 단일로 사용하기보다는 사용자의 이용량이 적은 새벽 시간대에 통계 작업을 위해 처리하는 경우가 많기 때문에 Spring Scheduler나 Quartz를 연동해서 많이 처리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 개발단계에서는 스프링이 실행되면 Job이 자동으로 실행되기 때문에 이를 application.yml이나 설정 파일에서 스프링 배치 실행을 끄고 작업할 필요는 있다. 만약 스프링 부트 환경이라면 application.properties에 다음 속성을 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1734938547131&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring.batch.job.enabled=false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 예시&lt;/p&gt;
&lt;pre id=&quot;code_1734938569615&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
public class JobScheduler {

    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private Job exampleJob;

    @Scheduled(cron = &quot;0 0 2 * * ?&quot;)
    public void runJob() throws Exception {
        JobParameters params = new JobParametersBuilder()
                .addLong(&quot;time&quot;, System.currentTimeMillis())
                .toJobParameters();
        jobLauncher.run(exampleJob, params);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 Spring Batch를 사용할 경우가 뭐가 있을지 생각해보니, 일일 사용량과 같은 통계 데이터를 추출하거나, 특정 기간에 대한 정산 데이터를 구하기 위해서도 자주 사용하는 예시를 확인했다. 또한 개인적인 생각이지만 한 번 제대로 작성하고 나면 로직 자체가 변경되는 일이 많지 않을 것 같기 때문에 처음에 조금 정성들이는게 추후에 관리를 위해서도 좋을 것 같다.&lt;/p&gt;</description>
      <category>Web Programming</category>
      <category>spring</category>
      <category>spring Batch</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/111</guid>
      <comments>https://digitalagora.tistory.com/111#entry111comment</comments>
      <pubDate>Mon, 23 Dec 2024 16:26:02 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 4-4 자료구조. - 그래프</title>
      <link>https://digitalagora.tistory.com/110</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&quot;이것이 취업을 위한 컴퓨터 과학이다 with CS 기술면접&quot; 책을 참고했습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프는 연결 관계를 표현하는 자료구조이다. 네트워크, 운영체제 등 다양한 분야에서 범용적으로 사용하며, 알고리즘 분야에서도 자주 나오는 굉장히 중요한 자료구조라고 할 수 있다. 한 번 알아보자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 그래프의 종류와 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프란 &lt;b&gt;정점(vertex)&lt;/b&gt;이라 불리는 데이터를 &lt;b&gt;간선(edge) 혹은 링크(link)&lt;/b&gt;로 연결한 형태의 자료구조를 의미한다. 이전 시간에 학습했던 &lt;b&gt;트리&lt;/b&gt;구조 역시 노드와 노드를 간선으로 연결했었던 그래프의 일종으로, 노드 간의 상하 관계를 고려한 그래프라고 할 수 있다. 일반적인 그래프는 사이클(어떤 정점에서 다시 돌아올 경로가 있는 경우)을 형성하거나, 이웃한 정점끼리 별도의 상하 관계를 가지지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wQlf8/btsKoe1H1Dd/Y08IjWSktOkKNcKO7kXvy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wQlf8/btsKoe1H1Dd/Y08IjWSktOkKNcKO7kXvy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wQlf8/btsKoe1H1Dd/Y08IjWSktOkKNcKO7kXvy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwQlf8%2FbtsKoe1H1Dd%2FY08IjWSktOkKNcKO7kXvy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;350&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프는 기본적으로 데이터 간의 연결 관계를 표현하는 자료구조로, 우리 일상에서 다양한 분야에 이미 활용되고 있다. 지하철 노선도나 통신 기기간의 연결 네트워크 등 꽤나 익숙한 형태로 우리에게 가까이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프는 앞에서 말했듯 연결 관계를 표현하기 때문에 간선이 중요한 역할을 맡으며 간선의 형태에 따라 그래프의 종류가 달라질 수 있다. 대표적인 종류는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;연결 그래프 / 비연결 그래프&lt;/b&gt; : 모든 정점이 간선으로 단 하나의 간선으로라도 갈 가능성이 존재하는지 여부
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결 그래프 : 그래프 상에 있는 임의의 두 정점 사이의 경로가 존재하는 그래프&lt;/li&gt;
&lt;li&gt;비연결 그래프 : 어떤 정점 사이에는 경로가 없는 경우가 존재하는 그래프&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방향 / 무방향 그래프&lt;/b&gt; : 방향이 있는지 없는지 여부&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가중치 그래프&lt;/b&gt; : 간선에 가중치가 있는 그래프를 의미하며, 가중치를 비용이라고도 부른다.(정점 사이의 거리라든지)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서브 그래프 : &lt;/b&gt;부분 그래프라도 불리며 트리에서의 부분 트리와 유사한 개념이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 그래프들의 표현 방식으로는 크게 2가지가 있다. 하나는 인접 행렬 기반으로 표현하는 것이 있고, 다른 하나는 인접 리스트로 표현하는 방식이 있다. 하나씩 알아보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2 인접 행렬 기반 그래프 표현&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접행렬 기반 그래프 표현은 &lt;b&gt;N * N&lt;/b&gt; 크기의 단위행렬로 그래프를 표현하는 방식이다. &lt;b&gt;N은 정점의 개수&lt;/b&gt;를 말하며, N * N 행렬의 &lt;b&gt;&amp;lt;행, 열&amp;gt; 값은 &amp;lt;출발 정점, 도착 정점&amp;gt;을 의미&lt;/b&gt;한다. 두 정점이 연결되어 있다면 1, 그렇지 않다면 0으로 표기한다. 예를 들어 아래와 같은 그래프에 대해서 인접 행렬로 표현하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;558&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yyCP8/btsKqAVVY36/04kF1KqxmqvhnOAzjW3hS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yyCP8/btsKqAVVY36/04kF1KqxmqvhnOAzjW3hS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yyCP8/btsKqAVVY36/04kF1KqxmqvhnOAzjW3hS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyyCP8%2FbtsKqAVVY36%2F04kF1KqxmqvhnOAzjW3hS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;352&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;558&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 93px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;From \ To&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;1번&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;2번&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;3번&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;4번&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;1번&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 21px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;2번&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;3번&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;4번&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방향 그래프라면 이야기가 다르겠지만, 무방향 그래프의 경우 위와 같은 특징이 존재한다. 바로&amp;nbsp;&lt;b&gt;대각선 요소를 기준으로 연결 관계가 대칭을 이룬다는 점이다.(한쪽이 연결되면 From To를 뒤집어도 성립하기 때문)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 그래프가 가중치 그래프라면 1과 0이 아니라 1 대신 가중치를 기반으로 작성하면 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3 인접 리스트 기반 그래프 표현&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접 리스트 기반 표현 방식은 말처럼 특정 정점과 연결된 정점들을 연결 리스트의 형태로 표현하는 방법이다. 각각의 정점마다 연결 리스트를 가질 텐데 특정 정점에서 나가는 간선에 연결된 정점들을 연결 리스트의 노드로 표현한다. 위의 예시를 인접 리스트로 표현하면 다음과 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 89px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;시작 정점&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;2 , N(가중치가 있다면)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 가중치 그래프라면 노드의 번호와 가중치를 묶어서 연결 리스트에 추가하면 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-4 장단점과 실제 구현&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 가지 표현 방법 모두 좋지만, 장단점을 고려해 코드를 작성하면 좋다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 85px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 13.7984%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 40.7752%; height: 17px;&quot;&gt;인접 행렬&lt;/td&gt;
&lt;td style=&quot;width: 45.4263%; height: 17px;&quot;&gt;연결 리스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 13.7984%; height: 34px;&quot; rowspan=&quot;2&quot;&gt;장점&lt;/td&gt;
&lt;td style=&quot;width: 40.7752%; height: 17px;&quot;&gt;간선의 존재 여부를 O(1)로 확인 가능하다.&lt;/td&gt;
&lt;td style=&quot;width: 45.4263%; height: 17px;&quot;&gt;메모리 사용량이 O(V + E)로 희소 그래프의 경우 더 메모리를 효율적으로 사용할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.7752%; height: 17px;&quot;&gt;구현이 쉽다.&lt;/td&gt;
&lt;td style=&quot;width: 45.4263%; height: 17px;&quot;&gt;간선의 순회가 더 쉽다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 13.7984%; height: 34px;&quot; rowspan=&quot;2&quot;&gt;단점&lt;/td&gt;
&lt;td style=&quot;width: 40.7752%; height: 17px;&quot;&gt;메모리 사용량이 O(V^2)로 정점 수가 많을 경우 굉장히 비효율적이다.&lt;/td&gt;
&lt;td style=&quot;width: 45.4263%; height: 17px;&quot; rowspan=&quot;2&quot;&gt;간선의 존재 여부를 확인하려면 O(V) 시간 복잡도가 필요하다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.7752%; height: 17px;&quot;&gt;희소 그래프(노드보다 간선 수가 적은 경우)의 경우 공간 낭비가 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.7984%;&quot;&gt;효율성&lt;/td&gt;
&lt;td style=&quot;width: 40.7752%;&quot;&gt;밀집 그래프의 경우 용이&lt;/td&gt;
&lt;td style=&quot;width: 45.4263%;&quot;&gt;희소 그래프의 경우 용이&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;실제 코드 구현&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접 행렬&lt;/p&gt;
&lt;pre id=&quot;code_1730268188615&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class AdjacencyMatrixGraph {
    private int[][] matrix; // 인접 행렬
    private int vertices; // 정점 수

    // 생성자
    public AdjacencyMatrixGraph(int vertices) {
        this.vertices = vertices;
        matrix = new int[vertices][vertices]; // 정점 수에 맞는 2차원 배열 생성
    }

    // 간선 추가
    public void addEdge(int source, int destination) {
        matrix[source][destination] = 1; // 간선 존재
        matrix[destination][source] = 1; // 무방향 그래프인 경우
    }

    // 그래프 출력
    public void printGraph() {
        for (int i = 0; i &amp;lt; vertices; i++) {
            for (int j = 0; j &amp;lt; vertices; j++) {
                System.out.print(matrix[i][j] + &quot; &quot;);
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4);
        graph.addEdge(0, 1);
        graph.addEdge(0, 2);
        graph.addEdge(1, 2);
        graph.addEdge(2, 3);

        System.out.println(&quot;인접 행렬:&quot;);
        graph.printGraph();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;결과&lt;/p&gt;
&lt;pre id=&quot;code_1730268199104&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;인접 행렬:
0 1 1 0 
1 0 1 0 
1 1 0 1 
0 0 1 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;인접 리스트&lt;/p&gt;
&lt;pre id=&quot;code_1730268211362&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.ArrayList;
import java.util.List;

public class AdjacencyListGraph {
    private List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; adjList; // 인접 리스트

    // 생성자
    public AdjacencyListGraph(int vertices) {
        adjList = new ArrayList&amp;lt;&amp;gt;();
        for (int i = 0; i &amp;lt; vertices; i++) {
            adjList.add(new ArrayList&amp;lt;&amp;gt;()); // 각 정점에 대한 리스트 생성
        }
    }

    // 간선 추가
    public void addEdge(int source, int destination) {
        adjList.get(source).add(destination); // 정점에 간선 추가
        adjList.get(destination).add(source); // 무방향 그래프인 경우
    }

    // 그래프 출력
    public void printGraph() {
        for (int i = 0; i &amp;lt; adjList.size(); i++) {
            System.out.print(i + &quot;: &quot;);
            for (Integer vertex : adjList.get(i)) {
                System.out.print(vertex + &quot; &quot;);
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        AdjacencyListGraph graph = new AdjacencyListGraph(4);
        graph.addEdge(0, 1);
        graph.addEdge(0, 2);
        graph.addEdge(1, 2);
        graph.addEdge(2, 3);

        System.out.println(&quot;인접 리스트:&quot;);
        graph.printGraph();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;결과&lt;/p&gt;
&lt;pre id=&quot;code_1730268234508&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;인접 리스트:
0: 1 2 
1: 0 2 
2: 0 1 3 
3: 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 그래프의 정의와 그래프를 구현하는 방법에 대해서 알아보았다. 다음 시간에는 그래프의 탐색 방법인 DFS, BFS, 그리고 다익스트라 알고리즘에 대해 차근차근 알아보자.&lt;/p&gt;</description>
      <category>Computer Science</category>
      <category>bfs</category>
      <category>cs</category>
      <category>dfs</category>
      <category>그래프</category>
      <category>다익스트라</category>
      <category>오블완</category>
      <category>자료구조</category>
      <category>최단 경로</category>
      <category>티스토리챌린지</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/110</guid>
      <comments>https://digitalagora.tistory.com/110#entry110comment</comments>
      <pubDate>Thu, 7 Nov 2024 17:39:49 +0900</pubDate>
    </item>
    <item>
      <title>[백준][Java] 2609 - 최대공약수와 최소공배수</title>
      <link>https://digitalagora.tistory.com/109</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제 링크&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2609&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2609&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제 풀이 과정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대공약수와 최소공배수 문제에 대해 효율적으로 풀기 위해서는 유클리드 호제법에 따라 최대공약수를 푸는 방법에 대해 알아야 손쉽게 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유클리드 호제법이란 2개의 자연수에 대한 최대공약수를 구하는 방식이다. 쉽게 설명하면 두 수 a,b에 대해서 더 작은 수로 나눈 나머지로 끊임없이 0이 될때까지 나누는걸 의미한다. 이걸 쉽게 설명하려면 아래 예시가 가장 쉽게 이해가 된다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 1500 &amp;divide; 326&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1500을 326으로 나눈 몫은 &lt;b&gt;4&lt;/b&gt;이고, 나머지는 &lt;b&gt;196&lt;/b&gt;이야.&lt;/li&gt;
&lt;li&gt;즉, 1500 &amp;divide; 326 = 4 (몫), 나머지 &lt;b&gt;196&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 326 &amp;divide; 196&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이제 326을 196으로 나눠. 몫은 &lt;b&gt;1&lt;/b&gt;이고, 나머지는 &lt;b&gt;130&lt;/b&gt;이야.&lt;/li&gt;
&lt;li&gt;즉, 326 &amp;divide; 196 = 1 (몫), 나머지 &lt;b&gt;130&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 196 &amp;divide; 130&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;196을 130으로 나누면, 몫은 &lt;b&gt;1&lt;/b&gt;이고, 나머지는 &lt;b&gt;66&lt;/b&gt;이야.&lt;/li&gt;
&lt;li&gt;즉, 196 &amp;divide; 130 = 1 (몫), 나머지 &lt;b&gt;66&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 130 &amp;divide; 66&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;130을 66으로 나누면, 몫은 &lt;b&gt;1&lt;/b&gt;이고, 나머지는 &lt;b&gt;64&lt;/b&gt;야.&lt;/li&gt;
&lt;li&gt;즉, 130 &amp;divide; 66 = 1 (몫), 나머지 &lt;b&gt;64&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 66 &amp;divide; 64&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;66을 64로 나누면, 몫은 &lt;b&gt;1&lt;/b&gt;이고, 나머지는 &lt;b&gt;2&lt;/b&gt;야.&lt;/li&gt;
&lt;li&gt;즉, 66 &amp;divide; 64 = 1 (몫), 나머지 &lt;b&gt;2&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 64 &amp;divide; 2&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마지막으로 64를 2로 나누면, 몫은 &lt;b&gt;32&lt;/b&gt;이고 나머지는 &lt;b&gt;0&lt;/b&gt;이 돼.&lt;/li&gt;
&lt;li&gt;즉, 64 &amp;divide; 2 = 32 (몫), 나머지 &lt;b&gt;0&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과:&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지가 0이 되었으므로, 이때 나누는 수인 &lt;b&gt;2&lt;/b&gt;가 1500과 326의 **최대공약수(GCD)**야.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정리:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;**1500과 326의 최대공약수(GCD)**는 &lt;b&gt;2&lt;/b&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시처럼 끊임없이 나누다보면 나머지가 0이 되는 순간이 곧 최대공약수인 지점이다. 최대공약수를 구했다면 최소공배수는 구하기 쉽다. 정리하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최소공배수 : 두 수 a * b / GCD(a,b)&lt;/li&gt;
&lt;li&gt;최대공약수 : 유클리드 호제법에 따라 나머지가 0인 지점의 나누는 수&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1712822003881&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class solution2609 {

    // 최소공배수와 최대공약수
    // 최대공약수는 유클리드 호제법에 따라
    // GCD(a,b) = GCD(b,a, mod b)
    // lcm(a,b) = a * b / GCD(a,b)
    public static int gcd(int a, int b) {
        while (b != 0) {
            int t = b;
            b = a % b;
            a = t;
        }
        return a;
    }

    public static int lcm(int a, int b) {
        return a * b / gcd(a, b);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int[] targetArray = new int[2];
        StringTokenizer st = new StringTokenizer(br.readLine(), &quot; &quot;);
        targetArray[0] = Integer.parseInt(st.nextToken());
        targetArray[1] = Integer.parseInt(st.nextToken());

        System.out.println(gcd(targetArray[0], targetArray[1]));
        System.out.println(lcm(targetArray[0], targetArray[1]));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;figure id=&quot;og_1729669533213&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;05. 유클리드 호제법&quot; data-og-description=&quot;[TOC] 수학 공식을 직접 코드로 바꾸는 알고리즘 문제는 잘 나오지는 않지만 가끔 필요할 때가 있습니다. 이럴 때 사용하기 위해서라도 기억을 꼭 해야 합니다. 대표적인 문제가&amp;hellip;&quot; data-og-host=&quot;wikidocs.net&quot; data-og-source-url=&quot;https://wikidocs.net/205459&quot; data-og-url=&quot;https://wikidocs.net/205459&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/IkiIC/hyXlVfZhho/XcbwQg9N2NA2TuWe1ydKk1/img.png?width=197&amp;amp;height=256&amp;amp;face=0_0_197_256&quot;&gt;&lt;a href=&quot;https://wikidocs.net/205459&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://wikidocs.net/205459&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/IkiIC/hyXlVfZhho/XcbwQg9N2NA2TuWe1ydKk1/img.png?width=197&amp;amp;height=256&amp;amp;face=0_0_197_256');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;05. 유클리드 호제법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[TOC] 수학 공식을 직접 코드로 바꾸는 알고리즘 문제는 잘 나오지는 않지만 가끔 필요할 때가 있습니다. 이럴 때 사용하기 위해서라도 기억을 꼭 해야 합니다. 대표적인 문제가&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;wikidocs.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩테스트/백준</category>
      <category>백준</category>
      <category>최대공약수</category>
      <category>최소공배수</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/109</guid>
      <comments>https://digitalagora.tistory.com/109#entry109comment</comments>
      <pubDate>Wed, 23 Oct 2024 16:45:43 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 4-3 자료구조. - 트리</title>
      <link>https://digitalagora.tistory.com/108</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&quot;이것이 취업을 위한 컴퓨터 과학이다 with CS 기술면접&quot; 책을 참고했습니다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 트리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리는 주로 계층적인 구조를 표현하기 위한 자료구조이다. 데이터가 저장되는 노드(node), 노드와 노드를 연결하는 간선(edge 혹은 link라고도 부른다.)으로 이루어져 있으며, 간선으로 연결된 노드는 상하 관계를 형성한다. 다양한 용어가 있는데, 차례대로 알아보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드 간 형성된 상하 관계에서 상위는 부모 노드, 하위는 자식 노드라고 부른다.&lt;/li&gt;
&lt;li&gt;두 개념 모두 상대적인 개념이기 때문에, 자식 노드이면서 부모 노드일 수 있다.&lt;/li&gt;
&lt;li&gt;노드는 하나 이상의 자식을 가질 수 있지만, 부모 노드는 하나만 있을 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;형제 노드(sibling node)&lt;/b&gt; : 같은 부모 노드를 공유하는 노드를 의미한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조상 노드(ancestor node)&lt;/b&gt; : 특정 노드에 대해 부모 노드와 그 부모 노드들을 지칭한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자손 노드(descendant node)&lt;/b&gt; : 특정 노드에 대해 자식 노드와 그 노드의 자식 노드들을 지칭한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;루트 노드(root node)&lt;/b&gt; : 부모 노드가 없는 최상단 노드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리프 노드(leaf node)&lt;/b&gt;&amp;nbsp;: 자식이 없는 최하단 노드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;차수(degree)&lt;/b&gt; : 각 노드가 가지는 자식 노드의 수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레벨(level)&lt;/b&gt; : 루트 노드에서 특정 노드까지 거치는 간선의 개수를 의미한다. 특정 노드가 얼마나 깊은 곳에 있는지를 뜻하는 트리의 깊이와 같은 개념이다.&lt;/li&gt;
&lt;li&gt;레벨 중 가장 높은 레벨이 곧 트리의 높이다.&lt;/li&gt;
&lt;li&gt;트리 안에 또 다른 트리 구조가 있을 수 있으며, 이를 &lt;b&gt;서브트리(subtree)&lt;/b&gt;라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 내용이 트리라는 자료구조를 이해함에 있어 필수적인 내용이다. 양이 많아 보이지만 결국 하나하나 트리 구조에 대해서 학습하다 보면 익숙해질 내용이니 어려워할 필요 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 실제로 메모리 상에 어떻게 구현하고 저장할 수 있을까? 다양한 구현 방식이 있겠지만, 연결리스트와 유사하게 &lt;b&gt;데이터를 저장할 공간 + 자식 노드의 위치 정보...&lt;/b&gt; 로 구성된다. 위치 정보는 자식 노드가 여러 개라면 그만큼 존재할 테니 하나는 아니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2 트리의 순회&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리의 모든 노드를 한 번씩 방문하는 것을 트리의 순회라고 부른다. 이런 트리의 순회 방식에는 크게 3가지가 있는데, 아래 트리 그림을 기준으로 차례대로 설명하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLupUT/btsKfFkktD7/7u8x6oNZkca0KFnKNdtk8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLupUT/btsKfFkktD7/7u8x6oNZkca0KFnKNdtk8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLupUT/btsKfFkktD7/7u8x6oNZkca0KFnKNdtk8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLupUT%2FbtsKfFkktD7%2F7u8x6oNZkca0KFnKNdtk8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1149&quot; height=&quot;642&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순회는 처음에 이해하기 난해할지도 모르지만, 각각 순서가 어떤지 보고 난 뒤 차근차근 설명하도록 하겠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전위 순회 : A -&amp;gt; B -&amp;gt; D -&amp;gt; H -&amp;gt; I -&amp;gt; E -&amp;gt; J -&amp;gt; K -&amp;gt; C -&amp;gt; F -&amp;gt; L -&amp;gt; G&lt;/li&gt;
&lt;li&gt;중위 순회 : H -&amp;gt; D -&amp;gt; I -&amp;gt; B -&amp;gt; J -&amp;gt; E -&amp;gt; K -&amp;gt; A -&amp;gt; L -&amp;gt; F -&amp;gt; C -&amp;gt; G&lt;/li&gt;
&lt;li&gt;후위 순회 : H -&amp;gt; I -&amp;gt; D -&amp;gt; J -&amp;gt; K -&amp;gt; E -&amp;gt; B -&amp;gt; L -&amp;gt; F -&amp;gt; G -&amp;gt; C -&amp;gt; A&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 전위 순회&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전위 순회는 루트 노드 -&amp;gt; 왼쪽 서브트리 전위 순회 -&amp;gt; 오른쪽 서브트리 전위 순회 순서&lt;/b&gt;를 가지고 있다. 위 그림을 기준으로 설명하면, 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;A&lt;/b&gt; 방문 후 왼쪽 서브트리의 루트 노드인 &lt;b&gt;B&lt;/b&gt;를 방문.&lt;/li&gt;
&lt;li&gt;B를 기준으로 왼쪽 서브트리의 루트 노드인 &lt;b&gt;D&lt;/b&gt; 방문.&lt;/li&gt;
&lt;li&gt;D를 기준으로 왼쪽 서브 트리의 루트 노드인 &lt;b&gt;H&lt;/b&gt; 방문.&lt;/li&gt;
&lt;li&gt;H 이하 노드가 없기 때문에 바로 상위 노드의 오른쪽 노드인 &lt;b&gt;I&lt;/b&gt; 방문.&lt;/li&gt;
&lt;li&gt;I 이하 노드가 없기 때문에 순회하지 않은 &lt;b&gt;E&lt;/b&gt; 노드를 방문&lt;/li&gt;
&lt;li&gt;E 노드에서 D와 동일하게 왼쪽(&lt;b&gt;J&lt;/b&gt;) -&amp;gt; 오른쪽(&lt;b&gt;K&lt;/b&gt;) 탐색.&lt;/li&gt;
&lt;li&gt;더 이상 최상위 루트 노드 기준 왼쪽 노드가 없기 때문에 &lt;b&gt;C&lt;/b&gt; 노드 방문.&lt;/li&gt;
&lt;li&gt;앞의 순회와 동일하게 왼쪽을 최우선해서 &lt;b&gt;F, I&lt;/b&gt; 탐색 후 &lt;b&gt;G&lt;/b&gt; 노드 방문.&lt;/li&gt;
&lt;li&gt;전위 순회 : A -&amp;gt; B -&amp;gt; D -&amp;gt; H -&amp;gt; I -&amp;gt; E -&amp;gt; J -&amp;gt; K -&amp;gt; C -&amp;gt; F -&amp;gt; L -&amp;gt; G&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방문 과정은 굉장히 복잡해보이지만, 이걸 의사 코드로 구현하면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1729660993648&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;전위 순회(노드) : 
	if 노드가 존재하지 않으면:
    	return
    노드 값 출력
    전위 순회(노드의 왼쪽 자식)
    전위 순회(노드의 오른쪽 자식)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 중위 순회&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;중위 순회는 전위 순회와 달리 왼쪽 서브트리 중위 순회 -&amp;gt; 루트 노드 -&amp;gt; 오른쪽 서브트리 중위 순회의 순서&lt;/b&gt;를 가지고 있다. 위 트리를 순회하는 과정을 보면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 A의 왼쪽 서브트리 중 가장 왼쪽인 D가 루트 노드인 서브 노드를 방문한다.&lt;/li&gt;
&lt;li&gt;D를 기준으로 중위순회를 하므로, 위 중위 순회의 순서처럼 &lt;b&gt;H -&amp;gt; D -&amp;gt; I&lt;/b&gt; 를 차례대로 방문한다.&lt;/li&gt;
&lt;li&gt;이제 왼쪽 서브트리가 끝났으므로, &lt;b&gt;B&lt;/b&gt;(루트)를 방문한 뒤, 오른쪽 서브트리에 방문한다.&lt;/li&gt;
&lt;li&gt;오른쪽 서브트리(E)의 왼쪽부터 차례대로 &lt;b&gt;J -&amp;gt; E -&amp;gt; K&lt;/b&gt;를 방문한다.&lt;/li&gt;
&lt;li&gt;왼쪽 서브트리가 전체적으로 끝났으므로 이제 루트 노드인 &lt;b&gt;A&lt;/b&gt;를 방문하고 오른쪽 서브트리를 중위 순회한다.&lt;/li&gt;
&lt;li&gt;오른쪽 서브트리(C)의 왼쪽 서브트리를 중위 순회(&lt;b&gt;I -&amp;gt; F&lt;/b&gt;) 후 루트 노드 방문(&lt;b&gt;C&lt;/b&gt;) 후 마지막 오른쪽 노드(&lt;b&gt;G&lt;/b&gt;)를 방문하면 끝난다.&lt;/li&gt;
&lt;li&gt;중위 순회 : H -&amp;gt; D -&amp;gt; I -&amp;gt; B -&amp;gt; J -&amp;gt; E -&amp;gt; K -&amp;gt; A -&amp;gt; L -&amp;gt; F -&amp;gt; C -&amp;gt; G&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중위 순회의 의사코드는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1729661418831&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;중위 순회(노드):
	if 노드가 존재하지 않으면 :
    	return
    중위 순회(노드의 왼쪽 자식)
    노드 값 출력
    중위 순회(노드의 오른쪽 자식)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) 후위 순회&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 후위 순회에 대해 알아보자. &lt;b&gt;후위 순회는 왼쪽 서브트리 후위 순회 -&amp;gt; 오른쪽 서브트리 후위 순회 -&amp;gt; 루트 노드의 방문 순서&lt;/b&gt;를 지니고 있다. 이 같은 순서를 기억하고 위 트리를 기준으로 설명하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 왼쪽 서브트리인 D를 기준으로 후위순회 하므로 &lt;b&gt;H&lt;/b&gt;를 방문한 다음, 오른쪽 &lt;b&gt;I&lt;/b&gt;를 방문하고 루트 노드인 &lt;b&gt;D&lt;/b&gt;를 방문한다.&lt;/li&gt;
&lt;li&gt;그다음 루트 노드인 B를 기준으로 왼쪽이 끝났으니 오른쪽 서브트리를 후위 순회한다.&lt;/li&gt;
&lt;li&gt;오른쪽 서브트리에서 차례대로 왼쪽, 오른쪽, 루트를 방문한다.&lt;b&gt;(J -&amp;gt; K -&amp;gt; E)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;B의 자식 노드를 모두 탐색했으므로 마지막 루트 노드인 &lt;b&gt;B&lt;/b&gt;를 방문한다.&lt;/li&gt;
&lt;li&gt;이제 A를 기준으로 오른쪽 서브트리에서 앞의 과정을 반복해서 차례대로 방문한다.&lt;b&gt;(L -&amp;gt; F -&amp;gt; G -&amp;gt; C)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;모두 방문했으면 마지막으로 &lt;b&gt;A&lt;/b&gt;를 방문한다.&lt;/li&gt;
&lt;li&gt;후위 순회 : H -&amp;gt; I -&amp;gt; D -&amp;gt; J -&amp;gt; K -&amp;gt; E -&amp;gt; B -&amp;gt; L -&amp;gt; F -&amp;gt; G -&amp;gt; C -&amp;gt; A&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후위 순회의 의사 코드는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1729662009016&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;후위 순회(노드):
	if 노드가 존재하지 않으면:
    	return
    후위 순회(노드의 왼쪽 자식)
    후위 순회(노드의 오른쪽 자식)
    노드 값 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 3가지 순회에 대해 간단히 정리하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;전위 순회 : 루트 노드 -&amp;gt; 왼쪽 서브트리 전위 순회 -&amp;gt; 오른쪽 서브트리 전위 순회&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중위 순회 : 왼쪽 서브트리 중위 순회 -&amp;gt; 루트 노드 -&amp;gt; 오른쪽 서브트리 중위 순회&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후위 순회 : 왼쪽 서브트리 후위 순회 -&amp;gt; 오른쪽 서브트리 후위 순회 -&amp;gt; 루트 노드&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3 트리의 종류&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리에는 순회 방법뿐만 아니라 상황에 따라 다양한 트리가 사용될 수 있다. 트리의 종류는 꽤 다양하며 대표적인 것들에 대해서만 차례대로 알아보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 이진 트리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 노드의 개수가 2개 이하인 트리를 말한다. 트리라고 말하면 떠올리는 대표적인 형태의 트리로 이진트리의 형태에 따라 조금씩 다르게 부르기도 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;편향된 이진트리 : 자식 노드가 한 쪽으로만 치우치게 생성된 이진 트리&lt;/li&gt;
&lt;li&gt;정 이진 트리 : 자식 노드의 개수가 0, 혹은 2개인 경우&lt;/li&gt;
&lt;li&gt;포화 이진 트리 : 리프 노드를 제외한 모든 노드가 자식을 2개씩 가지고 있고, 모든 리프 노드의 레벨이 동일한 경우&lt;/li&gt;
&lt;li&gt;&lt;b&gt;완전 이진트리(complete binary tree)&lt;/b&gt; : 리프 노드를 제외한 모든 노드가 자식을 2개씩 가지고 있고, 리프 노드가 왼쪽부터 순서대로 존재하는 경우&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이진 탐색 트리(BST)&lt;/b&gt; : 탐색에 활용되는 이진트리로 특정 노드를 기준으로 왼쪽은 모두 값이 작고, 오른쪽은 그 노드보다 큰 값을 지닌 형태의 이진 트리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;O(log n)으로 원하는 값을 탐색할 수 있는 장점이 있음.&lt;/li&gt;
&lt;li&gt;다만 단점으로 편향된 이진 탐색 트리라면 O(n)의 시간이 걸림.(최악)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;힙(heap)&lt;/b&gt; : BST와 유사하게 탐색에 특화된 완전 이진 트리로 2가지 종류가 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최소 힙 : 부모 노드가 자식 노드의 값보다 작은 값으로 이루어짐&lt;/li&gt;
&lt;li&gt;최대 힙 : 부모 노드가 자식 노드의 값보다 큰 값으로 이루어짐.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자가 균형 이진 탐색 트리&lt;/b&gt; : 이진 탐색 트리의 단점을 해결해 왼쪽과 오른쪽 서브 트리의 균형을 맞추는 트리로 크게 &lt;b&gt;AVL 트리와 RB 트리가 존재한다.&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;RB 트리 :&amp;nbsp;&lt;/b&gt;노드에 색을 칠하는 규칙과 칠해진 색(블랙, 레드)을 기준으로 균형을 맞춘다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;루트, 리프 노드는 블랙이다.&lt;/li&gt;
&lt;li&gt;레드 노드의 자식 노드는 블랙 노드.&lt;/li&gt;
&lt;li&gt;루트 노드에서 임의의 리프 노드에 이르는 경로의 블랙 노드 수는 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AVL 트리 :&lt;/b&gt; RB 트리보다 조금 더 엄격한 규칙으로 좌우 자식 간의 높이 차이를 기준으로 균형을 맞춘다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;B 트리 : RB 트리와 유사하게 균형을 유지하는 트리이지만, &lt;b&gt;다진 탐색 트리의 한 종류&lt;/b&gt;이다. 다진 탐색 트리는 여러 자식 노드를 가질 수 있는 트리를 의미한다. B 트리는 실무에서 파일 시스템이나 DB에서 자주 사용된다.(현재는 B+ 트리도 많이 사용한다.)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 노드가 가질 수 있는 최대 자식 노드의 개수가 M개인 B 트리를 M차 B트리라고 한다.&lt;/li&gt;
&lt;li&gt;M차 B트리의 최소 자식 노드의 개수는 (루트, 리프 제외)[M / 2] 개다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 트리의 종류는 더 많고 다양하며, 트리의 순회 방식에 대해서도 저 방식 이외에 방법도 존재한다. 추후에 찾아보는 것을 권장하며 마지막으로 관련된 추천 용어 정도만 남기겠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레벨 순서 순회&lt;/li&gt;
&lt;li&gt;AVL, RB, B, B+ 트리&lt;/li&gt;
&lt;li&gt;세그먼트 트리&lt;/li&gt;
&lt;li&gt;펜윅 트리&lt;/li&gt;
&lt;li&gt;트라이&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;figure id=&quot;og_1729662831739&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[자료구조] 이진 트리 &amp;amp; 이진 탐색 트리 (BST: Binary Search Tree) - 하나몬&quot; data-og-description=&quot;이진 트리 &amp;amp; 이진 탐색 트리 (BST: Binary Search Tree) 알아보기 ❗️여러 가지 트리의 모습 트리 구조는 편리한 구조를 전시하는 것 외에 효율적인 탐색을 위해 사용하기도 한다. 수많은 선배 개발자&quot; data-og-host=&quot;hanamon.kr&quot; data-og-source-url=&quot;https://hanamon.kr/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%9D%B4%EC%A7%84-%ED%8A%B8%EB%A6%AC-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%ED%8A%B8%EB%A6%AC-bst-binary-search-tree/&quot; data-og-url=&quot;https://hanamon.kr/자료구조-이진-트리-이진-탐색-트리-bst-binary-search-tree/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bdy8wk/hyXlVUyZ5y/pNxdz03OFzk7tlTYMRyClk/img.png?width=1280&amp;amp;height=844&amp;amp;face=0_0_1280_844,https://scrap.kakaocdn.net/dn/7dgfM/hyXlQ6MTgG/Rmm0uveLHKXzbEfgPNJOI0/img.png?width=1280&amp;amp;height=844&amp;amp;face=0_0_1280_844,https://scrap.kakaocdn.net/dn/8dxtp/hyXlIgB7U9/AsQJyraLcdcyvYZiXcLjR1/img.jpg?width=1032&amp;amp;height=291&amp;amp;face=0_0_1032_291&quot;&gt;&lt;a href=&quot;https://hanamon.kr/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%9D%B4%EC%A7%84-%ED%8A%B8%EB%A6%AC-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%ED%8A%B8%EB%A6%AC-bst-binary-search-tree/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hanamon.kr/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%9D%B4%EC%A7%84-%ED%8A%B8%EB%A6%AC-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%ED%8A%B8%EB%A6%AC-bst-binary-search-tree/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bdy8wk/hyXlVUyZ5y/pNxdz03OFzk7tlTYMRyClk/img.png?width=1280&amp;amp;height=844&amp;amp;face=0_0_1280_844,https://scrap.kakaocdn.net/dn/7dgfM/hyXlQ6MTgG/Rmm0uveLHKXzbEfgPNJOI0/img.png?width=1280&amp;amp;height=844&amp;amp;face=0_0_1280_844,https://scrap.kakaocdn.net/dn/8dxtp/hyXlIgB7U9/AsQJyraLcdcyvYZiXcLjR1/img.jpg?width=1032&amp;amp;height=291&amp;amp;face=0_0_1032_291');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[자료구조] 이진 트리 &amp;amp; 이진 탐색 트리 (BST: Binary Search Tree) - 하나몬&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이진 트리 &amp;amp; 이진 탐색 트리 (BST: Binary Search Tree) 알아보기 ❗️여러 가지 트리의 모습 트리 구조는 편리한 구조를 전시하는 것 외에 효율적인 탐색을 위해 사용하기도 한다. 수많은 선배 개발자&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hanamon.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1729663230323&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[자료구조] Red-Black tree / AVL tree&quot; data-og-description=&quot;Red-Black 트리와 AVL 트리는 평균적인 실행 속도를 개선하기 위한 이진 탐색 트리이다. 두 트리를 어떨 때 사용하면 좋을지 비교해보자.&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@cedongne/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Red-Black-tree-AVL-tree&quot; data-og-url=&quot;https://velog.io/@cedongne/자료구조-Red-Black-tree-AVL-tree&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QMjGp/hyXlXrky8J/itsEY4U863S0687sLYMpL1/img.png?width=768&amp;amp;height=402&amp;amp;face=0_0_768_402,https://scrap.kakaocdn.net/dn/BoQ4u/hyXlV1lBJ1/wNO4BDXy46HImWQVE1CWHk/img.png?width=768&amp;amp;height=402&amp;amp;face=0_0_768_402,https://scrap.kakaocdn.net/dn/czqfUi/hyXlHWkRw7/WjEQ9MCrPCvWVbjXhTmK0k/img.png?width=768&amp;amp;height=402&amp;amp;face=0_0_768_402&quot;&gt;&lt;a href=&quot;https://velog.io/@cedongne/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Red-Black-tree-AVL-tree&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@cedongne/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Red-Black-tree-AVL-tree&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QMjGp/hyXlXrky8J/itsEY4U863S0687sLYMpL1/img.png?width=768&amp;amp;height=402&amp;amp;face=0_0_768_402,https://scrap.kakaocdn.net/dn/BoQ4u/hyXlV1lBJ1/wNO4BDXy46HImWQVE1CWHk/img.png?width=768&amp;amp;height=402&amp;amp;face=0_0_768_402,https://scrap.kakaocdn.net/dn/czqfUi/hyXlHWkRw7/WjEQ9MCrPCvWVbjXhTmK0k/img.png?width=768&amp;amp;height=402&amp;amp;face=0_0_768_402');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[자료구조] Red-Black tree / AVL tree&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Red-Black 트리와 AVL 트리는 평균적인 실행 속도를 개선하기 위한 이진 탐색 트리이다. 두 트리를 어떨 때 사용하면 좋을지 비교해보자.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science</category>
      <category>cs</category>
      <category>이진 트리</category>
      <category>자료구조</category>
      <category>트리</category>
      <category>트리 순회</category>
      <category>트리의 종류</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/108</guid>
      <comments>https://digitalagora.tistory.com/108#entry108comment</comments>
      <pubDate>Wed, 23 Oct 2024 15:02:37 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 4-2 자료구조. - 배열, 연결리스트, 스택 &amp;amp; 큐, 해시 테이블</title>
      <link>https://digitalagora.tistory.com/107</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&quot;이것이 취업을 위한 컴퓨터 과학이다 with CS 기술면접&quot; 책을 참고했습니다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 배열 &amp;amp; 연결리스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어를 기반으로 학습을 단 한 번이라도 해봤다면 익숙한 자료구조인 배열과 연결리스트다. 배열과 연결리스트는 상황에 따라서 다른 자료구조를 만드는 재료로도 활용되기 때문에 깊게 이해하는 것이 좋다. 차근차근 알아보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1 배열&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;배열(Array)이란 일정한 메모리 공간을 차지하는 여러 요소들이 순차적으로 나열된 자료구조를 의미한다.&amp;nbsp;&lt;/b&gt;각 요소에는 0부터 시작하는 고유한 순서 번호인 인덱스가 매겨지며, 이 인덱스를 기준으로 요소들을 식별할 수 있다. 다음과 같은 특징을 지닌다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 요소 접근 시간은 요소의 개수와 무관하게 일정한 &lt;b&gt;O(1)이다.&lt;/b&gt; 인덱스만 찾아서 조회하면 되기 때문.&lt;/li&gt;
&lt;li&gt;앞에서부터 차례대로 특정 요소를 찾아나간다면 연산 시간은 &lt;b&gt;O(N)&lt;/b&gt;이다. N개의 요소를 차례대로 탐색하기 때문.&lt;/li&gt;
&lt;li&gt;특정 요소를 추가, 삭제, 수정하는 경우에도 시간 복잡도는 &lt;b&gt;O(N)&lt;/b&gt;이다. 중간에 추가되거나 삭제되는 요소로 인해 이후 요소들이 이동해야 되기 때문.&lt;/li&gt;
&lt;li&gt;배열은 크기가 고정되었는지 아닌지에 따라서 정적 배열과 동적 배열로 나뉜다. 일반적으로 우리가 배열이라고 지칭할 때는&lt;b&gt; 정적 배열&lt;/b&gt;을 의미하며 크기가 고정되어 있는 형태이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 코드에서 실제 배열을 선언하고 활용하는 방법을 예시로 보게 되면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1729138627018&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
    // 다양한 선언 및 초기화
        int[] numList = new int[10];
        int[] numList2 = {1,2,3,4,5,6,7,8,9,10};
        int[] numList3 = new int[]{1,2,3,4,5,6,7,8,13,14};

	// 선언만 했을 경우 데이터 저장.
        for(int i = 0; i &amp;lt; numList.length; i++) {
            numList[i] = i;
        }

	// 각각 조회
        for(int i = 0; i &amp;lt; numList.length; i++) {
            System.out.println(numList[i]);
        }
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 역사가 오래된 C++, C, Java 같은 경우, 배열은 크기가 고정되어 있고, 배열 선언 시 받을 데이터 타입에 대해서 한 가지만 받을 수 있는 특징이 있다. 이는 메모리 관리의 효율성을 고려해 설계된 부분이며 위에서 설명하는 배열의 이론적인 부분과 가장 친숙하게 맞닿아 있는 부분이기도 하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2 연결리스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결리스트는 노드의 모음으로 구성된 자료구조이다. &lt;b&gt;노드란 연결리스트의 구성 단위로, 저장하고자 하는 데이터와 다음 노드의 메모리 상의 주소 정보&lt;/b&gt;를 포함한다. 어느 노드에 접근한다면, 그 노드에 담긴 정보에 따라 그 다음 노드의 정보도 알 수 있고 이 과정이 순차적으로 반복적으로 이루어지게 된다. 이 점을 인지하고 연결리스트의 특징을 정리하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결리스트의 첫 번째 노드는&lt;b&gt; 헤드&lt;/b&gt;, 마지막 노드는 &lt;b&gt;꼬리(tail)&lt;/b&gt;라고 부른다.&lt;/li&gt;
&lt;li&gt;배열과 달리 &lt;b&gt;반드시 메모리에 순차적으로 저장되어 있을 필요가 없기&lt;/b&gt; 때문에, 연속적으로 구성되어 있는 데이터를 불연속적으로 저장할 때 유용하게 사용가능하다.&lt;/li&gt;
&lt;li&gt;연결리스트는 특정 요소에 접근하려면 앞에서부터 순차적으로 노드를 찾아서 접근해야하므로, 탐색 시간은 &lt;b&gt;O(N)&lt;/b&gt;이다.&lt;/li&gt;
&lt;li&gt;노드의 위치만 바꾸면 되기 때문에 추가, 삭제가 매우 빠르다. 탐색 시간은&lt;b&gt; O(1)&lt;/b&gt;이다.&lt;/li&gt;
&lt;li&gt;기본적으로 순차적으로 한 방향으로 헤드에서 꼬리 방향으로 이루어지는 연결리스트를 싱글 연결 리스트라고 한다.&lt;/li&gt;
&lt;li&gt;싱글 연결 리스트는 다음 노드는 알 수 있지만, 이전 노드는 알기 어려운 단점이 있다.&lt;/li&gt;
&lt;li&gt;싱글 연결 리스트를 보완하기 위해 나온 이중 연결 리스트는 &lt;b&gt;한 노드에 이전 노드에 대한 정보도 포함하고 있다. 다만 그만큼 더 많은 저장 공간을 필요로 한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;꼬리 노드가 헤드 노드를 가리켜 노드들이 원형으로 구성된 경우 환형 연결 리스트라고 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서 실제 코드의 예시를 보면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1729139935897&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.LinkedList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List&amp;lt;String&amp;gt; list = new LinkedList&amp;lt;&amp;gt;();

        list.add(&quot;hello&quot;);
        list.add(&quot;hello2&quot;);
        list.add(&quot;hello3&quot;);
        list.add(1,&quot;hello1&quot;);

        for (String s : list) {
            System.out.println(s);
        }

        list.remove(0);
        list.remove(&quot;hello2&quot;);

    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 순차적으로 저장하거나, 특정 위치에 저장해 사용 가능하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 스택 &amp;amp; 큐&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1 스택&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택은 한 쪽에서만 데이터의 삽입 삭제가 가능한 자료구조를 의미하며, 흔히 박스 쌓기나, 과자 통 같은 경우로 비유가 되며, 특징은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장하는 연산은 &lt;b&gt;push&lt;/b&gt;, 데이터를 빼내는 연산은 &lt;b&gt;pop&lt;/b&gt; 이라고 한다.&lt;/li&gt;
&lt;li&gt;스택은 &lt;span style=&quot;background-color: #f89009;&quot;&gt;&lt;b&gt;후입선출(LIFO)&lt;/b&gt;&lt;/span&gt; 구조로 나중에 넣은 데이터가 가장 먼저 나오게 된다.&lt;/li&gt;
&lt;li&gt;스택은 여러가지 경우에 사용 가능하지만, 가장 유용한 상황은 다음과 같다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;최근에 임시 저장한 데이터를 가장 먼저 활용해야 할 때&lt;/b&gt; 많이 사용된다. 운영체제에서 스택 영역의 경우, 함수의 실행이 끝나면 더 이상 필요 없는 지역변수, 매개변수, 함수 복귀 정보 같은 함수 호출 정보는 사용이 끝나면 제일 먼저 삭제해야할 정보이므로 스택 구조는 유용하게 사용된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;뒤로가기 기능을 만들고&lt;/b&gt; 싶을 때 사용 가능하다. 예를 들어 웹 브라우저에서 뒤로가기 버튼의 경우, 스택에 차례대로 URL 주소를 저장해놨다가 뒤로 가기 버튼을 누르면 최근 주소를 빼내고 이전 주소로 찾아가면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택의 경우 코드로 구현하면 다음과 같다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1729143002717&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Stack;

public class StackExample {
    public static void main(String[] args) {
        Stack&amp;lt;Integer&amp;gt; stack = new Stack&amp;lt;&amp;gt;();
        
        // 스택에 값 추가 (push)
        stack.push(10);
        stack.push(20);
        stack.push(30);

        System.out.println(&quot;Stack: &quot; + stack);
        
        // 스택에서 값 꺼내기 (pop)
        System.out.println(&quot;Popped: &quot; + stack.pop());
        System.out.println(&quot;Popped: &quot; + stack.pop());
        
        System.out.println(&quot;Stack after pops: &quot; + stack);
        
        // 스택의 최상단 값 확인 (peek)
        System.out.println(&quot;Peek: &quot; + stack.peek());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1729143030185&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Stack: [10, 20, 30]
Popped: 30
Popped: 20
Stack after pops: [10]
Peek: 10&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2 큐&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택과 달리 큐는 한쪽으로 데이터를 삽입하고, 다른 한 쪽으로 데이터를 삭제하는 자료구조이다. 비유를 들 때, 일종의 터널로 많이 비유하기도 한다. 특징은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큐는 데이터가 삽입되면(First In) 데이터가 가장 먼저 나오게 된다(First Out). 이런 점 때문에 큐를 &lt;span style=&quot;background-color: #f89009;&quot;&gt;&lt;b&gt;선입선출(FIFO)&lt;/b&gt;&lt;/span&gt; 자료구조라고 이야기한다.&lt;/li&gt;
&lt;li&gt;큐의 한 쪽 킅에 데이터를 삽입하는 연산을 &lt;b&gt;enqueue&lt;/b&gt;, 데이터를 삭제하는 연산을 &lt;b&gt;dequeue&lt;/b&gt; 라고 한다.&lt;/li&gt;
&lt;li&gt;임시 저장된 데이터를 차례차례 가져와야 하는 각종의 &lt;b&gt;Buffer&lt;/b&gt;로도 많이 활용된다. 즉 줄을 세워야하는 경우 많이 사용한다고 보면 된다.&lt;/li&gt;
&lt;li&gt;큐는 다양한 형태로 변형되는데, 대표적으로 원형 큐, 덱, 우선순위 큐 등이 대표적이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원형 큐 : 데이터를 삽입하는 쪽, 삭제하는 쪽을 하나로 연결해 원형으로 사용되는 구조&lt;/li&gt;
&lt;li&gt;덱(deque) : 양방향 큐(double-ended queue)의 약자로, 양쪽으로 데이터의 삽입 삭제가 가능한 구조&lt;/li&gt;
&lt;li&gt;우선순위 큐(priority queue) : 정해진 우선순위가 높은 순으로 처리되는 큐를 말하며, 추후 학습할 트리와 힙이라는 자료구조를 기반으로 구현된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐의 경우 코드로 구현하면 다음과 같다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1729143404014&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.LinkedList;
import java.util.Queue;

public class QueueExample {
    public static void main(String[] args) {
        Queue&amp;lt;Integer&amp;gt; queue = new LinkedList&amp;lt;&amp;gt;();
        
        // 큐에 값 추가 (offer) [enqueue]
        queue.offer(10);
        queue.offer(20);
        queue.offer(30);

        System.out.println(&quot;Queue: &quot; + queue);
        
        // 큐에서 값 꺼내기 (poll) [dequeue]
        System.out.println(&quot;Polled: &quot; + queue.poll());
        System.out.println(&quot;Polled: &quot; + queue.poll());
        
        System.out.println(&quot;Queue after polls: &quot; + queue);
        
        // 큐의 첫 번째 값 확인 (peek)
        System.out.println(&quot;Peek: &quot; + queue.peek());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1729143413241&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Queue: [10, 20, 30]
Polled: 10
Polled: 20
Queue after polls: [30]
Peek: 30&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 해시 테이블&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 테이블(hash table)은 키(key)와 값(value)의 쌍으로 이루어진 표와 같은 형태의 자료구조를 말한다. 키는 해시 테이블에 대한 입력이고, 값은 키를 통해서 얻고자 하는 구체적인 데이터를 의미한다. 현실에서는 전화번호부라던지, 도서관의 도서 고유 번호라던지 다양한 방면에서 활용되고 있다. 해시 테이블의 특징은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터는 버킷(bucket)에 저장되어 있다. 버킷은 여러 개 존재하며, 여러 버킷들은 배열을 형성한다.&lt;/li&gt;
&lt;li&gt;해시 함수는 키를 인자로 활용해서 버킷 배열의 인덱스를 반환하여 원하는 곳에 접근할 수 있게 만들어준다.&lt;/li&gt;
&lt;li&gt;해시 함수의 연산 방법을&amp;nbsp;&lt;b&gt;해시 알고리즘&lt;/b&gt;이라고 하는데, 대표적으로 MD5, SHA-1, SHA-256, SHA-512, SHA3 등이 있다.&lt;/li&gt;
&lt;li&gt;같은 데이터라 하더라도 알고리즘이 달라지면 도출되는 해시 값이 달라진다.&lt;/li&gt;
&lt;li&gt;해시 테이블을 사용하는 가장 큰 이유는 key를 활용한&amp;nbsp;&lt;b&gt;빠른 검색 속도&lt;/b&gt;이다. 일반적인 상황에서 해시 테이블은 검색, 삽입, 삭제 연산의 경우 시간 복잡도는 &lt;b&gt;O(1) &lt;/b&gt;이다.&lt;/li&gt;
&lt;li&gt;다만 속도가 빠른 만큼, 많은 메모리 공간을 소모한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서로 다른 키에 대해서 같은 해시 값이 나오는 경우를 해시 충돌&lt;/b&gt;이라고 하는데, 이를 해결하기 위한 방법으로 체이닝과 개방 주소법이 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;체이닝 : &lt;/b&gt;충돌이 발생한 데이터를 연결 리스트로 추가하는 방법으로, 단순하게 해결할 수 있지만, 충돌의 양이 많아질 경우 속도가 느려져 해시 테이블의 장점이 빛이 바랠 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개방 주소법&lt;/b&gt; : 충돌 발생 시 , 충돌이 발생한 버킷의 인덱스가 아닌 다른 인덱스에 데이터를 저장하는 방법이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;충돌 발생 시 비어 있는 다른 버킷의 인덱스를 찾는 과정을 조사(probe)한다고 표현한다.&lt;/li&gt;
&lt;li&gt;조사 방법에 따라 선형 조사법, 이차 조사법 등으로 나뉜다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이중 해싱&lt;/b&gt; : 2개의 해시 함수를 사용하는 방법으로, 충돌 발생 시 나머지 해시 함수에 대한 해시 값만큼 떨어진 거리에 위치한 인덱스를 찾는 방식이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 해시 테이블을 구현하는 방법은 크게 HashTable과 HashMap이 있는데, HashTable은 동기화를 고려해 성능이 조금 떨어지고, HashMap의 경우 동기화를 고려하지 않아 속도가 상대적으로 더 빠르다. 코드는 아래와 같다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1729144518540&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.HashMap;

public class HashMapExample {
    public static void main(String[] args) {
        // HashMap 생성
        HashMap&amp;lt;String, Integer&amp;gt; hashMap = new HashMap&amp;lt;&amp;gt;();
        
        // 값 추가 (put)
        hashMap.put(&quot;Apple&quot;, 3);
        hashMap.put(&quot;Banana&quot;, 5);
        hashMap.put(&quot;Orange&quot;, 2);

        // 값 출력
        System.out.println(&quot;HashMap: &quot; + hashMap);
        
        // 특정 키의 값 가져오기 (get)
        int appleCount = hashMap.get(&quot;Apple&quot;);
        System.out.println(&quot;Apple count: &quot; + appleCount);
        
        // 특정 키의 값 업데이트
        hashMap.put(&quot;Apple&quot;, 4);
        System.out.println(&quot;Updated HashMap: &quot; + hashMap);
        
        // 특정 키의 존재 여부 확인 (containsKey)
        if (hashMap.containsKey(&quot;Banana&quot;)) {
            System.out.println(&quot;Banana is available.&quot;);
        }
        
        // 모든 키와 값 출력 (entrySet)
        for (var entry : hashMap.entrySet()) {
            System.out.println(&quot;Key: &quot; + entry.getKey() + &quot;, Value: &quot; + entry.getValue());
        }
        
        // 값 삭제 (remove)
        hashMap.remove(&quot;Orange&quot;);
        System.out.println(&quot;After removing Orange: &quot; + hashMap);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1729144530144&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap: {Apple=3, Banana=5, Orange=2}
Apple count: 3
Updated HashMap: {Apple=4, Banana=5, Orange=2}
Banana is available.
Key: Apple, Value: 4
Key: Banana, Value: 5
Key: Orange, Value: 2
After removing Orange: {Apple=4, Banana=5}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 여러 자료구조에 대해서 간단하게 알아봤다. 다만 이론적인 내용이다보니 조금 간단하게 적고 실제 코드로 적용하는 부분 위주로 작성했다.. 다음 시간에는 이번에 못다룬 트리와 그래프에 대해서 다룰 예정이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;figure id=&quot;og_1729143863981&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[CS - 자료구조] 해시 테이블 (Hash Table) 개념 정리&quot; data-og-description=&quot;오늘 공부해 볼 주제는 해시 테이블이다.해싱을 통해서 데이터를 저장하는 자료구조다.즉, 해시 함수를 사용해서 변환한 값을 색인(index)로 사용해 키(key)와 데이터(값, value)를 저장하는 자료구&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@dlgosla/CS-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%ED%95%B4%EC%8B%9C-%ED%85%8C%EC%9D%B4%EB%B8%94-Hash-Table-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-wb6g3iw0&quot; data-og-url=&quot;https://velog.io/@dlgosla/CS-자료구조-해시-테이블-Hash-Table-개념-정리-wb6g3iw0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bVf6RI/hyXlV6OgBw/JMmx9z8WgqsPxijakbJ7u1/img.png?width=1280&amp;amp;height=719&amp;amp;face=0_0_1280_719,https://scrap.kakaocdn.net/dn/q6TAV/hyXlVlqX8N/ehGKLEpTwYUf1d39I9JfL1/img.png?width=1280&amp;amp;height=719&amp;amp;face=0_0_1280_719,https://scrap.kakaocdn.net/dn/4oZQB/hyXhTQlqZf/nBxHhJeKkXwe8nPp7PHbR1/img.png?width=1280&amp;amp;height=719&amp;amp;face=0_0_1280_719&quot;&gt;&lt;a href=&quot;https://velog.io/@dlgosla/CS-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%ED%95%B4%EC%8B%9C-%ED%85%8C%EC%9D%B4%EB%B8%94-Hash-Table-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-wb6g3iw0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@dlgosla/CS-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%ED%95%B4%EC%8B%9C-%ED%85%8C%EC%9D%B4%EB%B8%94-Hash-Table-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-wb6g3iw0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bVf6RI/hyXlV6OgBw/JMmx9z8WgqsPxijakbJ7u1/img.png?width=1280&amp;amp;height=719&amp;amp;face=0_0_1280_719,https://scrap.kakaocdn.net/dn/q6TAV/hyXlVlqX8N/ehGKLEpTwYUf1d39I9JfL1/img.png?width=1280&amp;amp;height=719&amp;amp;face=0_0_1280_719,https://scrap.kakaocdn.net/dn/4oZQB/hyXhTQlqZf/nBxHhJeKkXwe8nPp7PHbR1/img.png?width=1280&amp;amp;height=719&amp;amp;face=0_0_1280_719');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[CS - 자료구조] 해시 테이블 (Hash Table) 개념 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘 공부해 볼 주제는 해시 테이블이다.해싱을 통해서 데이터를 저장하는 자료구조다.즉, 해시 함수를 사용해서 변환한 값을 색인(index)로 사용해 키(key)와 데이터(값, value)를 저장하는 자료구&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science</category>
      <category>cs</category>
      <category>배열</category>
      <category>스택</category>
      <category>연결리스트</category>
      <category>자료구조</category>
      <category>컴퓨터 구조</category>
      <category>큐</category>
      <category>해시 테이블</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/107</guid>
      <comments>https://digitalagora.tistory.com/107#entry107comment</comments>
      <pubDate>Thu, 17 Oct 2024 14:57:09 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 4-1. 자료구조 - 개요</title>
      <link>https://digitalagora.tistory.com/106</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&quot;이것이 취업을 위한 컴퓨터 과학이다 with CS 기술면접&quot; 책을 참고했습니다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 자료구조 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 말 그대로 데이터를 어떻게 효율적으로 관리하고 저장할지에 대해서 다루는 부분이다. 다양한 자료구조가 있겠지만, 대표적인 자료구조 위주로 학습할 예정이며 자료구조와 연관된 개념인 알고리즘, 그리고 시간, 공간 복잡도에 대해서도 차근차근 확인해보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1 자료구조와 알고리즘&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 컴퓨터 구조와 운영체제를 학습하면서 자료구조에 대해서 간접적으로나마 다루었던 내용이 있었다. 예를 들어 메모리 내에 존재하는 스택 영역의 스택이나 CPU 스케줄링에 대해서 설명하면서 스케줄링 큐 같은 개념이 자료구조의 일종이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 알고리즘은 무엇일까? 알고리즘은 간단하게 말하면 어떤 목적 달성을 위해 필요한 일련의 연산 절차를 의미한다. &lt;b&gt;자료구조가 앞에서 말했던 것처럼 데이터를 효율적으로 저장하고 관리하기 위한 방법을 다룬다면, 알고리즘은 그걸 활용해서 어떤 목적 달성을 위해 효율적으로 연산하는 방법을 다룬다고 생각하면 된다.&amp;nbsp;&lt;/b&gt;다만 오늘의 목표는 자료구조이기 때문에 별도로 적지는 않겠지만, 자료구조를 학습하는 과정에서 필요한 알고리즘 개념은 차근차근 설명할 예정이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2 시간 복잡도와 공간 복잡도&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 시간 복잡도&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 설명했던 것처럼 자료구조와 알고리즘을 고려해서 코드를 작성한다면 그렇지 않은 코드보다 훨씬 효율적이고 성능이 좋은 코드가 작성될 확률이 높다. 다만 어떤 자료구조와 알고리즘이 현재의 목적에 따라 효율적이고 &lt;b&gt;성능이 좋은지를 판단하는 기준&lt;/b&gt;이 뭘까? 그게 바로 시간 복잡도와 공간 복잡도이며, 이 두 복잡도는 소스 코드, 혹은 프로그램이 얼마나 효율적으로 동작하는지를 판단하는 기준이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시간 복잡도란 입력의 크기에 따른 프로그램 실행 시간의 관계&lt;/b&gt;를 의미한다. 프로그램의 실행 시간과 입력의 크기는 밀접한 관계가 있는데, 예를 들어보자. 만약 서로 다른 N개의 데이터를 하나씩 검사해서 특정 데이터를 찾는 프로그램이 있다고 한다면, 입력이 1 ~ 10개라면 금방하겠지만, 만약 10억개가 넘는 N개가 있다면 훨씬 오래걸릴 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도를 표현할 때, 대중적으로는&amp;nbsp;&lt;b&gt;빅오 표기법&lt;/b&gt;이 사용된다. 빅오 표기법은 아래와 같이 사용된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;O(N) =&amp;gt; 입력의 크기 N에 대한 빅오 표기법&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빅오 표기법&lt;/b&gt;은 &lt;b&gt;함수의 점근적 상한을 표기하는 방법&lt;/b&gt;이다. 여기서 점근적 상한은 '입력에 따른 실행 시간의 점근적 상한'을 의미하는데, 점근적 상한은 구체적으로 뭘 의미하는걸까? 예를 들어 입력하는 n 자체가 앞으로 무한히 커진다고 가정할 때, 시간 복잡도의 정의에 따라 실행 시간 역시 점진적으로 증가할 것이다. 하지만 실행 시간의 증가에도 한계가 있을텐데 이를&amp;nbsp;&lt;b&gt;점근적 상한&lt;/b&gt;이라고 한다. 위에 작성한 것처럼 N이라는 입력값에 대해서 그 값이 커지더라도&amp;nbsp;&lt;b&gt;실행 시간이 대략 이 상한보다는 커지지 않을 것이다&amp;nbsp;&lt;/b&gt;라는 뜻이다. 예를 들어 &lt;b&gt;O(N^2) &lt;/b&gt;이라는 빅오표기법이 있다면 이는 &lt;b&gt;&quot;입력값 N이 증가하더라도 실행 시간의 증가율은 N^2보다는 작다&lt;/b&gt;&lt;b&gt;&quot; &lt;/b&gt;라는 뜻으로 해석된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빅오 표기법 이외에도 빅 세타 표기법, 빅 오메가 표기법 등이 있는데, 간략히 설명하면 빅 세타는 입력에 대한 평균적인 실행 시간, 빅 오메가는 입력에 대한 실행 시간의 점근적 하한을 의미한다. 예를 들어 &amp;theta;(N^2) 이면 입력값 N이 증가해도 실행 시간의 증가율은 N^2와 같다라는 뜻이 되고, &amp;Omega;(N^2) 이면, 입력값 N이 증가하더라도 실행 시간의 증가율은 N^2보다는 크다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 설명했던 예시를 기반으로 빅오 표기법에 대해 설명해보자. 앞에서 서로 다른 N개의 데이터를 하나씩 검사해서 특정 데이터를 찾는 프로그램이 있다고 했었는데, 이걸 빅오 표기법으로 작성하면 &lt;b&gt;O(N)&lt;/b&gt;이 될 것이고, 이는 데이터를 하나씩 탐색해서 계산한다고 가정할 때 &lt;b&gt;N이 아무리 커진다 하더라도 탐색 과정이 N번 이상을 넘어가지는 않을 것&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빅오 표기법으로 점근적 상한을 표현할 때는&amp;nbsp;&lt;b&gt;최고차항의 차수&lt;/b&gt;만 고려한다. 즉 입력값 N에 대한 실행 시간을 수식으로 작성하면 그 중 최고 차항에 대해서만 고려한다. 이걸 감안하고나서 빅오 표기법으로 표현되는 시간 복잡도 중 자주 표현되는 표기는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MBBwT/btsJ2k1xd3F/5YKPvHWOJ0MBgjj0c0VLz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MBBwT/btsJ2k1xd3F/5YKPvHWOJ0MBgjj0c0VLz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MBBwT/btsJ2k1xd3F/5YKPvHWOJ0MBgjj0c0VLz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMBBwT%2FbtsJ2k1xd3F%2F5YKPvHWOJ0MBgjj0c0VLz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;638&quot; height=&quot;479&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 표의 특징과 각각의 시간 복잡도의 특징을 보게 되면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 속도 : &lt;b&gt;O(1) &amp;lt; O(log N) &amp;lt; O(N) &amp;lt; (O(N log N) &amp;lt; O(N^2) &amp;lt; O(2^N)&lt;/b&gt; 로 우측일수록 효율이 떨어짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;O(1)&lt;/b&gt; : 입력값이 증가해도 실행 시간은 동일한 경우로, index로 접근해서 바로 처리할 수 있는 연산 과정이 해당한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;stack의 push, pop&lt;/b&gt; 같은 기능이 해당.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;O(log N)&lt;/b&gt; : 연산이 한 번 수행될 때, 데이터의 크기가 절반 감소하는 알고리즘
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이진탐색이나, 트리 형태 자료구조의 탐색&lt;/b&gt;이 해당.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;O(N)&lt;/b&gt; : 입력값에 따라 실행 시간도 선형적으로 증가하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;1중 for문&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;O(N log N)&lt;/b&gt; : 입력 데이터가 많아질수록 처리 시간이 로그 배만큼 더 늘어나는 경우로, 데이터가 만약 10개 늘면 처리 시간은 20배가 늘어난다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;퀵, 병합, 힙 정렬&lt;/b&gt;이 이에 해당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;O(N^2)&lt;/b&gt; : 입력 데이터가 많아질수록 처리시간이 기하급수적으로 늘어남.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이중 for문, 삽입 정렬, 버블 정렬, 선택 정렬&lt;/b&gt; 등이 이에 해당.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;O(2^N)&lt;/b&gt; : 입력 데이터가 많아질수록 동일하게 처리시간이 기하급수적으로 늘어나는 형태.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;피보나치 수열, 재귀의 역기능&lt;/b&gt; 등이 이에 해당.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 공간 복잡도&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 알고리즘의 성능 파악을 위한 2가지 대표적인 지표 중 시간 복잡도에 대해 설명했었다. 공간 복잡도는 이름 그대로&amp;nbsp;&lt;b&gt;프로그램이 실행되었을 때, 필요한 메모리 자원의 양&lt;/b&gt;을 의미한다. 어떤 프로그램이더라도 결국 실행되기 위해서는 메모리에 적재되어야 하며, 사용량에 따라 필요한 메모리에 양이 많다면 공간 복잡도가 크다라고 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공간 복잡도 역시 시간 복잡도와 동일하게 빅오 표기법을 기반으로 표현하는데, 앞에서는 입력값에 따른 함수의 실행 시간이었다면 공간 복잡도에서의 빅오 표기법이 의미하는 바는&amp;nbsp;&lt;b&gt;입력에 따라 필요한 메모리 자원의 양에 대한 점근적 상한&lt;/b&gt;을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 알고리즘의 성능을 판단할 때는 시간 복잡도가 프로그램을 수행할 때 더 많이 고려되는 것이 일반적이며, 시간 복잡도와 공간 복잡도는 서로 반비례하는 경향이 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지가 자료구조에 대해서 학습하기 위해 필요한 정보들을 간략하게 정리해봤다. 좀 더 깊게 학습해야 될 내용은 별도로 학습하기로 하고, 다음 시간부터는 이제 차근차근 구체적인 자료구조들에 대해서 하나씩 알아보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;figure id=&quot;og_1728630767161&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[알고리즘] 시간 복잡도와 Big O 표기법&quot; data-og-description=&quot;✅ Big O 표기법 알고리즘의 효율에서 가장 중요한 부분은 &amp;lsquo;n이 커질 때 알고리즘의 단계가 얼마만큼 증가하는가&amp;rsquo;이고, 이것을 잘 나타내는 빅 O 표기법을 사용합니다. ►[알고리즘 + 자료구조 =&quot; data-og-host=&quot;www.hanbit.co.kr&quot; data-og-source-url=&quot;https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS7965376216&quot; data-og-url=&quot;https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS7965376216&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pUShK/hyXd3lq6CG/Ajky6hTOJf5LOb3kjbAuRk/img.png?width=600&amp;amp;height=600&amp;amp;face=0_0_600_600,https://scrap.kakaocdn.net/dn/iniZT/hyXec3JbSP/mdlQtM0pnRVV0mHxKvcmtk/img.png?width=800&amp;amp;height=596&amp;amp;face=0_0_800_596,https://scrap.kakaocdn.net/dn/Dn0aS/hyXhWSrkZz/X6idYiAmO7gRWryXbsRSN0/img.png?width=800&amp;amp;height=513&amp;amp;face=0_0_800_513&quot;&gt;&lt;a href=&quot;https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS7965376216&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS7965376216&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pUShK/hyXd3lq6CG/Ajky6hTOJf5LOb3kjbAuRk/img.png?width=600&amp;amp;height=600&amp;amp;face=0_0_600_600,https://scrap.kakaocdn.net/dn/iniZT/hyXec3JbSP/mdlQtM0pnRVV0mHxKvcmtk/img.png?width=800&amp;amp;height=596&amp;amp;face=0_0_800_596,https://scrap.kakaocdn.net/dn/Dn0aS/hyXhWSrkZz/X6idYiAmO7gRWryXbsRSN0/img.png?width=800&amp;amp;height=513&amp;amp;face=0_0_800_513');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[알고리즘] 시간 복잡도와 Big O 표기법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;✅ Big O 표기법 알고리즘의 효율에서 가장 중요한 부분은 &amp;lsquo;n이 커질 때 알고리즘의 단계가 얼마만큼 증가하는가&amp;rsquo;이고, 이것을 잘 나타내는 빅 O 표기법을 사용합니다. ►[알고리즘 + 자료구조 =&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.hanbit.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science</category>
      <category>cs</category>
      <category>공간복잡도</category>
      <category>시간복잡도</category>
      <category>자료구조</category>
      <category>컴퓨터 구조</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/106</guid>
      <comments>https://digitalagora.tistory.com/106#entry106comment</comments>
      <pubDate>Fri, 11 Oct 2024 16:12:54 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 3-3. 운영체제 - 가상 메모리, 파일 시스템</title>
      <link>https://digitalagora.tistory.com/105</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&quot;이것이 취업을 위한 컴퓨터 과학이다 with CS 기술면접&quot; 책을 참고했습니다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;1. 가상 메모리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간까지 우리는 운영체제에서 어떻게 멀티프로세스나 멀티스레드 환경에서 통신을 관리하고, CPU 자원을 효율적으로 활용하는지에 대해서 알아봤었다. 이번에는 운영체제의 메모리 관리 기법인 가상 메모리가 무엇인지에 대해서 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞의 내용을 본다면 자칫 CPU가 프로세스들이 메모리 속 어디에 저장되어 있는지 이미 알고 있다고 착각할지도 모른다. 하지만 그렇게 되면, 레지스터가 메모리만큼 커야 할 텐데 거기에는 무리가 있다. 또 사용 중이지 않은 프로세스는 메모리에서 해제된다. 그렇다면 어떻게 CPU는 메모리에 적재된 프로세스의 주소를 인식하고 관리할까? 이를 설명하기 위해 물리 주소와 논리 주소에 대해 먼저 이해해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1 물리 주소와 논리 주소&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU와 프로세스는 &lt;b&gt;실제 메모리의 하드웨어상 주소인 물리 주소&lt;/b&gt;가 아니라 다른 주소 체계를 사용하는데, 이게 논리 주소이다. &lt;b&gt;논리 주소란 프로세스마다 부여되는 0번지부터 시작하는 주소 체계&lt;/b&gt;를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물리 주소는 실제 하드웨어의 번지수이기 때문에 중복이 없지만, 중복되는 논리 주소는 얼마든지 존재할 수 있다. 하지만 결국 논리 주소더라도 실제 하드웨어 상의 메모리에 접근하려면 물리 주소로 변환하는 작업이 필요하다. 그렇지 않으면 CPU는 논리 주소로, 메모리는 물리 주소로 이야기할 테니 소통에 문제가 생기니 말이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;145&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgwsnc/btsJZly3xXR/AHVaTWTc16BuHcwcotYPhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgwsnc/btsJZly3xXR/AHVaTWTc16BuHcwcotYPhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgwsnc/btsJZly3xXR/AHVaTWTc16BuHcwcotYPhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdgwsnc%2FbtsJZly3xXR%2FAHVaTWTc16BuHcwcotYPhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;348&quot; height=&quot;145&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;145&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 필요한 것이 바로 &lt;b&gt;메모리 관리 장치(MMU, Memory Management Unit)&lt;/b&gt;이다. MMU는 CPU와 메모리 사이에 위치하며, &lt;b&gt;CPU가 이해하는 논리 주소를 메모리가 이해하는 물리 주소로 변환하는 역할&lt;/b&gt;을 한다. 그렇다면 이런 주소 체계와 변환 체계를 바탕으로 프로세스가 어떻게 구체적으로 메모리에 할당되는지에 대해서 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2 스와핑과 연속 메모리 할당&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 기본적인 메모리 할당방식은 스와핑과 연속 메모리 할당이다. 차근차근 알아보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 스와핑&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리에 적재된 프로세스 중에 현재 실행 중이지 않은 프로세스를 임시로 &lt;b&gt;스왑 영역(swap space)&lt;/b&gt;이라는 보조기억장치의 일부 영역으로 쫓아내고 그리고 생겨난 &lt;b&gt;빈 영역에 다른 프로세스를 적재하여 실행하는 메모리 관리 방식&lt;/b&gt;을 스와핑이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현재 실행되지 않는 프로세스를 메모리 -&amp;gt; 스왑 영역으로 옮겨지는 것을 스왑 아웃, 그 반대는 스왑 인&lt;/b&gt;이라고 한다. 스왑 아웃되어 스왑 영역에 옮겨졌던 프로세스가 다시 스왑 인이 되면, 그전에 있던 물리 주소와는 다른 주소에 적재될 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 연속 메모리 할당과 외부 단편화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스에 연속적인 메모리 공간을 차례차례 할당하는 방식을 &lt;b&gt;연속 메모리 할당&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스와핑이나 연속 메모리 할당 모두 뭔가 당연하다는 생각이 들 수 있지만, 실제로는 외부 단편화로 인해 효율적인 메모리 사용 방식일 수는 없다. &lt;b&gt;외부 단편화&lt;/b&gt;란 프로세스의 실행과 종료를 반복하다 보면, 메모리 사이에 빈 공간이 생기지만 그 공간이 프로세스를 적재하기에 적절하지 못해 그대로 빈 공간으로 남아 메모리 낭비로 이어지는 걸 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음과 같은 그림이 있다고 가정해 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/S0pB0/btsJZRK9UMQ/xIiFdSkM7gQTJu12fgKTkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/S0pB0/btsJZRK9UMQ/xIiFdSkM7gQTJu12fgKTkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/S0pB0/btsJZRK9UMQ/xIiFdSkM7gQTJu12fgKTkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FS0pB0%2FbtsJZRK9UMQ%2FxIiFdSkM7gQTJu12fgKTkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;333&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 프로세스 A와 C 사이에 C나 A 같은 프로세스를 하나 더 실행시키기에는 너무 공간이 좁아 빈 공간이 여전히 남게 되고, 이런 게 쌓이다 보면 메모리 낭비로 이어지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3 페이징을 통한 가상 메모리 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 살펴본 스와핑과 연속 메모리 할당은 2가지 문제가 있다. 하나는 적재와 삭제를 반복하며 프로세스 사이에 빈 공간이 생겨난 외부 단편화이고, 또 하나는 물리 메모리보다 큰 프로세스를 실행할 수 없다는 문제이다. 만약 프로세스를 반드시 연속적으로 할당해야 한다면 4GB 메모리로는 4GB 이상의 프로그램은 실행할 수 없을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 문제를 해결하기 위해 등장한 메모리 관리 기술이 가상 메모리이다.&amp;nbsp;&lt;b&gt;가상 메모리(virtual memory)란 실행하고자 하는 프로그램의 일부만 메모리에 적재해 실제 메모리보다 더 큰 프로세스를 실행할 수 있도록 만드는 메모리 관리 기법이다.&amp;nbsp;&lt;/b&gt;보조기억장치의 일부를 메모리처럼 사용하거나, 프로세스의 일부만 적재해 실제 크기보다 메모리르 더 크게 보이게 하는 기술이라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 가상 메모리 기법에는 페이징과 세그멘테이션이 있는데 페이징이 좀 더 범용적으로 많이 사용되니 페이징 위주로 알아보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 페이징&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;페이징(paging)은&lt;/b&gt;&amp;nbsp;프로세스의 &lt;b&gt;논리 공간을 페이지&lt;/b&gt;라는 일정한 단위로 나누고 &lt;b&gt;물리 주소 공간을 페이지&lt;/b&gt;와 동일한 크기의 프레임이라는 일정한 단위로 나눈 뒤 &lt;b&gt;페이지를 프레임에 할당하는 가상 메모리 관리 기법&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 메모리를 할당하게 되면, 외부 단편화가 발생할 수 없다. 빈 공간의 크기에 맞게 불연속적으로 할당할 수 있다면 빈 공간은 효율적으로 사용할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이징 기법에서도 스와핑이 사용될 수 있다. 다만 프로세스 전체가 메모리에서 스왑 아웃/인 되는 것이 아니라 필요에 따라서 페이지 단위로 스왑 아웃/인 된다. 페이징 기법에서의 스왑 아웃/인은 &lt;b&gt;페이지 아웃/인이라고 부른다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 페이징 기법에도 문제가 있는데, 물리 메모리 내에 페이지가 불연속적으로 중구난방 배치되어 있다면, CPU가 하나를 실행하고 다른 페이지를 실행할 때 탐색 시간이 오래 걸릴 수 있다. 이를 해결하기 위해 &lt;b&gt;페이지 테이블&lt;/b&gt;을 활용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bviSTh/btsJ0boWePC/r8qAVKhuwT8N54vepWKSKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bviSTh/btsJ0boWePC/r8qAVKhuwT8N54vepWKSKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bviSTh/btsJ0boWePC/r8qAVKhuwT8N54vepWKSKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbviSTh%2FbtsJ0boWePC%2Fr8qAVKhuwT8N54vepWKSKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;425&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지 테이블은 페이지 번호와 실제 적재된 프레임 번호가 대응된 형태로 적혀있다. CPU는 프로세스마다 고유의 페이지 테이블을 확인해 다음 페이지에 더 용이하게 접근할 수 있게 된다. 또한 페이지 테이블에는 페이지, 프레임 번호 이외에도 다른 중요한 번호가 있는데, 페이지 테이블에서&amp;nbsp;&lt;b&gt;각각 구성하는 행들을 페이지 엔트리라고 불리며 다음과 같은 형태를 띄운다.&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 34px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 13.5272%; height: 17px;&quot;&gt;페이지 번호&lt;/td&gt;
&lt;td style=&quot;width: 13.5271%; height: 17px;&quot;&gt;프레임 번호&lt;/td&gt;
&lt;td style=&quot;width: 15.0388%; height: 17px;&quot;&gt;유효 비트&lt;/td&gt;
&lt;td style=&quot;width: 16.2016%; height: 17px;&quot;&gt;수정 비트&lt;/td&gt;
&lt;td style=&quot;width: 16.0853%; height: 17px;&quot;&gt;참조 비트&lt;/td&gt;
&lt;td style=&quot;width: 25.6202%; height: 17px;&quot;&gt;보호 비트(r, w, x)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 13.5272%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 13.5271%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 15.0388%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 16.2016%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 16.0853%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25.6202%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 간략하게 설명하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 번호, 프레임 번호 : 앞에서 설명했듯 각각의 페이지와 프레임 번호가 적재&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유효 비트 : 해당 페이지에 접근 가능한 지 여부를 알려주는 비트&lt;/b&gt;. 페이지가 메모리에 적재되어 있으면 1, 아니면 0
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 메모리에 적재되어 있지 않은(유효 비트가 0인) 페이지에 접근하면 &lt;b&gt;page fault&lt;/b&gt;라는 exception 발생.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;처리 과정 : 기존 작업 백업 ➡ 폴트 처리 루틴 실행(페이지를 메모리에 적재 후 유효 비트 1로 변경) ➡ 페이지 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;보호 비트 : 페이지 보호 기능을 위해 존재하는 비트. 각각 읽기, 쓰기, 실행을 나타냄(read, write, execute)&lt;/li&gt;
&lt;li&gt;참조 비트 : CPU가 해당 페이지에 접근한 적 있는지를 나타내는 비트.&lt;/li&gt;
&lt;li&gt;수정 비트 : 해당 페이지에 데이터를 쓴 적이 있는지 여부를 알려주는 비트로 &lt;b&gt;dirty bit라고도&lt;/b&gt; 부른다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 수정했다면, 메모리에서 해제할 때 보조 기억장치에도 수정된 내용을 반영해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 페이지는 페이지테이블을 통해 다양한 기능들을 제공받고 효율적으로 메모리를 관리하지만, 앞에서 설명한 문제와 다른&amp;nbsp;&lt;b&gt;내부 단편화(internal fragmentation)&amp;nbsp;&lt;/b&gt;문제가 발생할 수 있다. 내부 단편화는 말 그대로 페이지 크기보다 작은 크기로 발생하게 되는 메모리 낭비이다. 예를 들어 페이지가 10KB인데, 프로세스가 107KB이라면, 마지막 페이지는 3KB 정도가 남는다.(10KB - 7KB) 즉 페이지 하나보다 작은 크기로 인해 발생하는 메모리 낭비 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 단편화와 별개로 또 한 가지 생각해봐야 할 문제가 하나 더 있다. 어떤 프로세스를 실행하려면 결국 페이지와 프레임의 정보가 담긴 페이지 테이블이 어디에 적재되는지도 알아야 하는데, 실행하고자 하는 모든 프로세스의 페이지 테이블을 메모리에 적재하고 있을까?&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;메모리에 적재된 페이지 테이블의 위치를 가리키는 레지스터를 &lt;b&gt;페이지 테이블 베이스 레지스터(PTBR)&lt;/b&gt;이라고 한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답은 &quot;&lt;b&gt;그럴 수도 있지만 운영체제는 지양한다&quot;이다.&lt;/b&gt; 모든 페이지 테이블을 메모리에 적재하는 것은 다음과 같은 문제가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;메모리 접근 횟수&lt;/b&gt; : CPU는 최소 메모리에 2번 접근해야 한다.(페이지, 페이지 테이블) 그렇게 되면 접근 시간이 2배로 늘어나는 문제가 있는데 이를 해결하기 위해 &lt;b&gt;TLB(translation Look-aside Buffer)라는&lt;/b&gt; 페이지 테이블의 캐시 메모리를 사용한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조 지역성의 원리에 근거해 자주 사용할 법한 페이지 위주로 테이블의 일부 내용을 저장한다.&lt;/li&gt;
&lt;li&gt;만약 TLB에 CPU가 접근할 페이지 정보가 있다면, TLB는 CPU에게 알려준다&lt;b&gt;(TLB 히트)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;만약 없다면, 다시 한번 페이지 메모리에 접근할 수밖에 없다.&lt;b&gt;(TLB 미스)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 용량 :&amp;nbsp;&lt;/b&gt;페이지 테이블은 생각보다 크다. 따라서 모든 페이지 테이블을 메모리에 두는 것은 용량의 낭비이다. 이를 해결하기 위해 등장한 방법 중 하나가 &lt;b&gt;계층적 페이징 기법이다. 이는 페이지 테이블 자체를 페이징 하는 기법&lt;/b&gt;으로 여러 단계의 페이지를 둔다는 점에서 다단계 페이지 테이블이라고 부르기도 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;페이징 시스템의 논리 주소는 페이지 번호, 변위(시작 번지로부터 얼마나 떨어져 있는지)의 형태로 이루어져 있다.&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;세그멘테이션은 간략하게만 알아보자.&lt;br /&gt;세그멘테이션(segmentation)은 프로세스를 고정된 크기의 페이지가 아니라&amp;nbsp;&lt;b&gt;가변적인 크기의 세그먼트 단위로 분할하는 방식이다.&lt;/b&gt; 다만 세그먼트의 크기가 일정하지 않아 외부 단편화가 발생할 수도 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-4 페이지 교체 알고리즘&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 페이지 전체가 모두 메모리에 적재될 필요는 없다고 1차적으로 언급했었다. 이처럼 &lt;b&gt;메모리에 필요한 페이지만을 적재하는 기법을 요구 페이징(demand paging)&lt;/b&gt;이라고 한다. 아래와 같은 양상을 띤다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 페이지에 접근하는 명령어 실행 ➡ 유효 비트가 1이면 프레임에 접근 ➡ 유효 비트가 0이면 페이지 폴트 ➡ 폴트 발생 시 메모리 적재 후 유효 비트 1로 변경 ➡다시 맨 처음부터 과정을 반복&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 아무것도 메모리에 적재하지 않고 일단 실행부터 하는 걸 순수 요구 페이징이라고 하는데, 의도적으로 처음부터 페이지 폴트를 발생시키고, 어느 정도 적재되고 나면 빈도는 줄어들게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨌든 요구 페이징을 통해서 점차 적재하다 보면 메모리가 가득 차게 될 것이고, 그 상황에서 메모리에 적재된 페이지 일부를 페이지 아웃해야 한다. 이때 페이지를 선택하는 효율적인 방법을 페이지 교체 알고리즘이라고 부른다. 대표적인 것은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FIFO 페이지 교체 알고리즘 : 가자 먼저 적재된 순부터 스왑 아웃. 잘 쓰고 있는 페이지도 스왑 아웃할 위험 있음.&lt;/li&gt;
&lt;li&gt;최적 페이지 교체 알고리즘 : 사용 빈도가 가장 낮은 페이지를 교체. 다만 미래 예측이 어려워 실제 구현이 힘듦.&lt;/li&gt;
&lt;li&gt;LRU 페이지 교체 알고리즘 : 가장 적게 사용한 페이지를 교체. 가장 보편적으로 현재 사용되는 알고리즘들의 원형&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 파일 시스템&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막으로 어떻게 운영체제가 보조기억장치를 효율적으로 관리하는지 알아보자. 파일시스템은 보조기억장치의 정보를 파일과 디렉터리의 형태로 저장하고 관리할 수 있도록 하는 운영체제 내부 프로그램이다. 한 운영체제 내에서도 여러 파일 시스템을 사용할 수 있고, 파일 시스템이 달라지면 보조기억장치의 정보를 다루는 방법도 달라지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1 파일과 디렉터리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 시스템 이전에 파일 시스템을 이루는 파일과 디렉터리가 뭔지 이해해보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 파일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일은 크게 파일의 이름, 파일을 실행하기 위한 정보, 관련된 부가 정보로 이루어져 있다. 여기서 부가 정보는 다른 이름으로 &lt;b&gt;속성(attribute) 혹은 메타데이터(metadata)&lt;/b&gt;로 불리는데, 파일의 형식, 위치, 크기 같은 정보들이 이에 해당한다. 파일을 수정하고 조작하는 행위는 운영체제가 담당하기 때문에 응용 프로그램이 접근할 수 없고 시스템 콜을 사용해 운영체제를 통해 조작해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 프로세스가 시스템 콜을 통해 10개의 파일을 할당받았다면, 현재 사용 중인 파일을 프로세스는 구분할 줄 알아야 한다. 이를 위해 프로세스는 &lt;b&gt;파일 디스크럽터(file descriptor, 윈도우는 file handle)&lt;/b&gt; 라는 정보를 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 디렉터리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일들을 효율적으로 관리하게 사용하는데, 윈도우에서는 폴더라고 부르기도 한다. 오늘날의 디렉터리는 트리 형태의 계층적 구조를 띄고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리 구조 디렉터리는 최상위의 루트 디렉터리와 그 하위의 서브 디렉터리의 계층적 구조로 구성되고, 우리가 일반적으로 pc에서 사용하는 경로느 디렉터리 정보를 활용해 파일 위치를 특정하는 정보를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 파일과 디렉터리를 구분하는 것처럼 설명하고 있지만, 운영체제에서는&amp;nbsp;&lt;b&gt;디렉터리를 디렉터리에 속한 요소의 관련 정보가 포함된 특별한 파일&lt;/b&gt; 정도로 간주한다. 디렉터리의 속한 요소의 관련 정보는 테이블의 형태로 디렉터리 엔트리가 행 별로 작성되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 운영체제에서 사용하는 디렉터리 엔트리는 다음과 같은 형태로 구성되어 있다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1728454499685&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct dirent {
    // 파일의 inode 번호. inode는 파일이나 디렉터리에 대한 메타데이터를 담고 있는 고유한 식별자
    ino_t d_ino;
    
    // 디렉터리 파일에서의 오프셋(위치). 이 값은 해당 디렉터리 엔트리가 디렉터리 파일 내에서 몇 번째에 위치하는지 나타냄
    off_t d_off;               
    
    // 디렉터리 엔트리의 레코드 길이. 즉, 이 `dirent` 구조체 하나의 크기를 의미
    unsigned short d_reclen;   
    
    // 파일의 타입을 나타내는 값. 파일인지 디렉터리인지, 심볼릭 링크인지 등을 구분할 수 있음.
    unsigned char d_type;      
    
    // 파일이나 디렉터리의 이름. 최대 255자의 이름을 저장할 수 있으며, 널 종료 문자열(`\0`)로 끝남.
    char d_name[256];          
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) 파일 할당&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략적으로 디렉터리와 파일이 어떻게 구현되어 있는지 이해했다면, 어떻게 보조기억장치에 구체적으로 저장되는지 알아보자. 운영체제는 파일과 디렉터리를 &lt;b&gt;블록(block)&lt;/b&gt;이라는 단위로 읽고 쓰는데, &lt;b&gt;블록은 대략 4096바이트의 크기&lt;/b&gt;를 지니고 있다. 파일 시스템에 따라서 블록에 파일 및 디렉터리를 저장하는 방식은 다양할 수 있지만, 대표적으로 2개만 설명하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결 할당 : 각 블록의 일부에 다음 블록의 주소를 저장해 점차 가리키는 형태로 저장.&lt;/li&gt;
&lt;li&gt;색인 할당 : 파일을 이루는 모든 블록의 주소를 색인 블록이라는 블록에 담고 관리하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2 파일 시스템&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 시스템은 정말 다양하며 운영체제 마다 여러 개의 파일 시스템을 선택해 사용할 수 있다. 어떤 파일 시스템을 사용할지는 보조기억장치를 &lt;b&gt;포매팅, 즉 파일 시스템을 설정하여 어떤 방식으로 파일을 관리할지 결정하고 새로운 데이터를 쓸 준비를 하는 단계에서 결정할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제마다 굉장히 다양한 파일 시스템을 사용하겠지만(NTFS, ReFS, EXT 시리즈, APFS 등) 가장 대표적인 리눅스에서 지원하는 파일 시스템의 경우(EXT1~4, XFS, ZFS)&amp;nbsp;&lt;span style=&quot;background-color: #f89009;&quot;&gt;&lt;b&gt;아이노드&lt;/b&gt;&lt;/span&gt;라는 색인 블록을 기반으로 파일을 할당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 추가적으로 USB 메모리 저장장치가 PC에 연결하면 사용할 수 있듯, 마운트를 통해서 서로 다른 파일 시스템끼리 접근하는 것도 가능하다.&amp;nbsp;&lt;b&gt;마운트란 어떤 저장장치의 파일 시스템에서 다른 저장장치의 파일 시스템으로 접근할 수 있도록 파일 시스템을 편입시키는 과정을 의미한다.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;figure id=&quot;og_1728450857497&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;페이징(Paging)과 페이지 테이블(Page table)&quot; data-og-description=&quot;페이징과 페이지 테이블은 현대 운영체제 메모리 관련 컨셉에서 아주 중요한 것이므로 잘 정리해두자!&amp;nbsp;&amp;nbsp;1. 페이징(Paging)&amp;nbsp;address space를 연속적으로 할당하지 말고, 페이지라는 단위로 쪼개서 사&quot; data-og-host=&quot;ddongwon.tistory.com&quot; data-og-source-url=&quot;https://ddongwon.tistory.com/49&quot; data-og-url=&quot;https://ddongwon.tistory.com/49&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dl3K6P/hyXd5QAhO7/ptBVkf7zyzwMzujuSrj6Mk/img.png?width=800&amp;amp;height=570&amp;amp;face=0_0_800_570,https://scrap.kakaocdn.net/dn/9AbpI/hyXd538R5b/qPLnTLCWnuDLYD5B75uZLk/img.png?width=800&amp;amp;height=570&amp;amp;face=0_0_800_570,https://scrap.kakaocdn.net/dn/bln6y1/hyXd6WgTev/Q12l5Ftk7OgnQYvydAvJ51/img.png?width=1176&amp;amp;height=838&amp;amp;face=0_0_1176_838&quot;&gt;&lt;a href=&quot;https://ddongwon.tistory.com/49&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ddongwon.tistory.com/49&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dl3K6P/hyXd5QAhO7/ptBVkf7zyzwMzujuSrj6Mk/img.png?width=800&amp;amp;height=570&amp;amp;face=0_0_800_570,https://scrap.kakaocdn.net/dn/9AbpI/hyXd538R5b/qPLnTLCWnuDLYD5B75uZLk/img.png?width=800&amp;amp;height=570&amp;amp;face=0_0_800_570,https://scrap.kakaocdn.net/dn/bln6y1/hyXd6WgTev/Q12l5Ftk7OgnQYvydAvJ51/img.png?width=1176&amp;amp;height=838&amp;amp;face=0_0_1176_838');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;페이징(Paging)과 페이지 테이블(Page table)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;페이징과 페이지 테이블은 현대 운영체제 메모리 관련 컨셉에서 아주 중요한 것이므로 잘 정리해두자!&amp;nbsp;&amp;nbsp;1. 페이징(Paging)&amp;nbsp;address space를 연속적으로 할당하지 말고, 페이지라는 단위로 쪼개서 사&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ddongwon.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science</category>
      <category>cs</category>
      <category>가상 메모리</category>
      <category>컴퓨터 구조</category>
      <category>파일 시스템</category>
      <category>페이징</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/105</guid>
      <comments>https://digitalagora.tistory.com/105#entry105comment</comments>
      <pubDate>Wed, 9 Oct 2024 15:24:10 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 3-2. 운영체제 - 동기화와 교착 상태, CPU 스케줄링</title>
      <link>https://digitalagora.tistory.com/104</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&quot;이것이 취업을 위한 컴퓨터 과학이다 with CS 기술면접&quot; 책을 참고했습니다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 동기화와 교착 상태&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 프로세스 간 통신에 대해 설명했는데, 그 상황을 한 번 상기해 보자. 프로세스 A가 공유 메모리 공간에 글을 쓰고 프로세스 B가 읽는다고 가정하면, 두 프로세스는 서로 같은 공간에서 자원을 공유하고 있다. 혹은 프로세스 내부의 스레드 2개가 프로세스가 할당받은 파일을 수정하게 되는 경우 두 스레드는 하나의 파일 자원을 공유하고 있다. 이렇게 프로세스나 스레드가 공유하는 자원은 &lt;b&gt;공유 자원(shared resource)&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 공유 자원을 다수의 프로세스나 스레드가 동시에 어떤 규칙 없이 마구잡이로 접근하게 된다면 어떻게 될까? 이때 공유 자원에 접근하는 코드 중 동시 실행 시 문제가 발생할 수 있는 코드는 &lt;b&gt;임계 구역(critical section)&lt;/b&gt;이라고 부르며, 이 임계 구역에 동시에 접근해서 실행하면 문제가 발생할 수 있다.&lt;br /&gt;앞에서 프로세스 A가 공유 메모리에 글을 쓰고, 프로세스 B가 읽는다고 했었다. 만약 실행 순서가 뒤바뀌게 된다면 아직 적히지 않은 메모리에 접근하려고 했기 때문에 오류가 발생하게 된다. 즉&amp;nbsp;&lt;b&gt;프로세스 A의 공유 메모리에 데이터를 쓰는 코드와 프로세스 B가 공유 메모리를 읽는 코드는 임계 구역이 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 동시에 임계 구역의 코드를 실행하여 문제가 발생하는 상황을 &lt;b&gt;레이스 컨디션(race condition)&lt;/b&gt;이라고 하며, 레이스 컨디션이 발생하면 데이터 일관성이 손상될 수 있기 때문에 하나가 실행되면 다른 작업은 그 작업이 끝날 때까지 대기해야 한다.&amp;nbsp;&lt;br /&gt;개발의 영역에서, 레이스 컨디션을 방지하고 임계 구역을 관리하기 위해서는 &lt;span style=&quot;background-color: #f89009;&quot;&gt;프로세스와 스레드가&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f89009;&quot;&gt;동기화(synchronization)&lt;/span&gt;되어야 한다.&lt;/b&gt; 동기화란 2가지 조건을 준수하여 실행하는 것을 의미한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;실행 순서 제어&lt;/b&gt; : 프로세스 및 스레드를 올바른 순서로 실행하기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상호 배제&lt;/b&gt; : 동시에 접근하면 안되는 자원에 하나의 프로세스 및 스레드만 접근하기&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2 동기화 기법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 순서와 상호 배제를 보장하기 위한 동기화 기법에는 무엇이 있는지 하나씩 알아보자. 참고로 앞으로 설명할 기능들은 대부분의 프로그래밍 언어에서 제공하고 있는 기능임을 인지하고 확인하자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;뮤텍스 락&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뮤텍스 락은 상호 배제를 보장하기 위한 동기화 도구로 다음과 같은 원리로 동작한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;임계 구역에 접근하고자 한다면 반드시 락을 획득해야 하고, 임계 구역에서 작업이 끝났다면 락을 해제해야 한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원리에서처럼, 전형적인 뮤텍스 락은 &lt;b&gt;프로세스나 스레드가 공유하는 변수 lock과 2개의 함수(acquire, release)&lt;/b&gt;로 구현된다. 임계 구역에 진입하려면 lock.acquire()를 통해 락을 획득하고, 작업이 끝나면 lock.release()를 통해 해제한다. lock.release 이전에 다른 작업이 lock.acquire()를 사용해 락을 얻으려고 해도 획득할 수 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++, 파이썬에서는 이미 뮤텍스 락이라는 이름으로 별도로 구현되어 있으며, 자바는 이름은 다르지만 ReentrantLock의 형태로 구현되어 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;세마포&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;뮤텍스 락은 하나의 공유 자원일때 사용하는 동기화 도구&lt;/b&gt;이다. 다만 늘 공유 자원이 하나만 있는 것은 아니다.&amp;nbsp;&lt;b&gt;세마포는 공유 자원이 여러 개일때 사용할 수 있는 동기화 도구이다.&lt;/b&gt; 뮤텍스 락과 유사하지만 좀 더 일반화된 방식의 동기화 도구이다. 세마포는 철도 신호기에서 유래한 단어로 철도 신호기를 떠올려보면, 신호기가 내려오면 stop, 올라가면 go라는 신호로 간주해 움직인다. 이처럼 임계구역에서 2가지 신호를 기반으로 관리한다. 세마포는 뮤텍스 락과 유사하게 하나의 변수와 두 개의 함수로 구성된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;변수 S&lt;/b&gt; : 사용 가능한 공유 자원의 개수를 나타내는 변수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;wait()&lt;/b&gt; : 임계 구역 진입 전 호출하는 함수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;signal()&lt;/b&gt; : 임계 구역 진입 후 호출하는 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 변수 S는&amp;nbsp;&lt;b&gt;임계구역에 진입할 수 있는 프로세스의 개수&lt;/b&gt;와 같다. 이 점을 인지하고 2 함수의 동작방식을 간단하게 설명하겠다.&lt;br /&gt;wait()는 함수 호출이 되면&amp;nbsp;&lt;b&gt;사용 가능한 공유 자원의 개수를 나타내는 변수 S를 1 감소시키고,&amp;nbsp;&lt;/b&gt;&lt;b&gt;변수 S의 값이 0보다 작은지 확인한다.&lt;/b&gt; 즉 공유 자원이 남아 있다면 wait()를 호출한 프로세스는 임계 구역에 진입할 수 있다. 만약 남아있지 않다면 wait()를 호출한 프로세스 및 스레드는 대기 상태로 전환되어 임계 구역에 진입할 수 없다.&amp;nbsp;&lt;br /&gt;반대로 signal()은 임계 구역에서 작업이 끝난 프로세스 혹은 스레드가 호출한다. 함수 호출이 되면&amp;nbsp;&lt;b&gt;사용 가능한 공유 자원의 개수를 나타내는 변수 S를 1 증가시키고, 변수 S의 값이 0 이하인지 확인한다.&amp;nbsp;&lt;/b&gt;만약 S가 0 이하라면,&amp;nbsp;&lt;b&gt;임계 구역 진입을 위해 대기하는 프로세스나 스레드가 있다는 의미이므로, 대기 상태의 프로세스 중 하나를 준비 상태로 변환한다.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;세마포는 크게 이진 세마포와 카운팅 세마포로 구분할 수 있다. 위에서 설명한 방식은 카운팅 세마포로, 이진 세마포는 S가 0과 1의 값만을 가지며, 뮤텍스락과 유사하게 동작한다. 따라서 일반적으로 세마포라 함은 카운팅 세마포를 의미한다.&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;조건 변수와 모니터&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모니터에 대해서 이해하기 위해서는 조건 변수에 대해서 먼저 이해해야 한다. &lt;b&gt;조건 변수란 실행 순서 제어를 위한 동기화 도구&lt;/b&gt;로 특정 조건에 따라 프로세스를 &lt;b&gt;실행 / 일시 중단 함&lt;/b&gt;으로써 실행 순서를 제어할 수 있다. 조건 변수는 wait()과 signal() 함수를 호출할 수 있는데 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;wait()&lt;/b&gt; : 아직 특정 프로세스가 실행될 조건이 되지 않았을 때, &lt;b&gt;실행을 중단한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;signal()&lt;/b&gt; : 특정 프로세스가 실행될 조건이 충족되었을 때, &lt;b&gt;실행을 재개한다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 2개의 쓰레드가 있는데, A가 cv라는 조건 변수에 대해 실행 도중 cv.wait()을 실행했다면, 다른 스레드에서 cv.signal()을 호출하기 전까지 대기 상태로 접어들게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모니터는 공유 자원과 그 공유 자원을 다루는 함수로 구성된 동기화 도구로, 상호 배제부터 실행 순서 제어를 위한 동기화까지 모두 가능하다. 작동 원리는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공유 자원 접근을 위해 정해진 공유 자원 연산을 통해 모니터 내로 접근한다.&lt;/li&gt;
&lt;li&gt;모니터 내에 진입하여 실행되는 프로세스(스레드)는 하나여야만 한다.&lt;/li&gt;
&lt;li&gt;이미 모니터 내에 프로세스(스레드)가 있다면 큐에서 대기해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 기본적으로 상호 배제를 구현하지만, 앞에서 설명한 조건 변수를 함께 사용한다면 실행 순서 제어도 가능하다. 말만 들으면 이해가 어려우니, 예시를 통해 확인해 보자.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;1. 동시에 실행되는 프로세스 A, B 중 반드시 A가 먼저 실행된다는 가정을 해본다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;2. 프로세스 B 실행 전에 프로세스 A의 실행이 끝났는지를 검사한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;3. 모니터 내에 진입해 프로세스 B가 실행된다면 프로세스 A는 실행이 종료된 것이므로 문제가 없다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;4. 그러나 프로세스 A가 종료되지 않았는데 B가 모니터 내로 진입했다면, cv.wait()을 통해 대기 상태로 변환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;5. 이후에 프로세스 A가 진입해 종료가 끝나면 cv.signal()을 호출해 종료됨을 알리고 프로세스 B를 실행한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 모니터를 활용한 동기화 방식을 쓰는 대표적인 예가 자바의 &lt;span style=&quot;background-color: #f89009;&quot;&gt;synchronized&lt;/span&gt; 키워드다. 아래와 같이 synchronized 키워드를 사용한 메서드는 하나의 프로세스(스레드)만 실행할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1728101676542&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public synchronized void example(int value){
	this.count += value;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스레드 안전&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어 공식 문서를 읽다 보면, 스레드 안전이라는 용어가 자주 나온다.&amp;nbsp;&lt;b&gt;스레드 안전이란 멀티스레드 환경에서 어떤 변수나 함수, 객체에 동시 접근이 이루어져도 실행에 문제가 없는 상태&lt;/b&gt;를 의미한다. 예를 들어 자바의 경우 ArrayList의 add 메서드는 스레드 안전하지 않지만, Vector의 add 메서드는 스레드 안전성이 보장되어 있다. 내부적으로 클래스를 살펴보면 vector의 경우 add 메서드에 synchronized 키워드로 구현되어 이를 보장한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3 교착 상태&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스를 실행하기 위해서는 자원이 필요한데, 만약 서로 다른 2개 이상의 프로세스가 각자 가지고 있는 자원을 무작정 기다리게 된다면 어떤 프로세스도 작업을 이어나갈 수 없는&amp;nbsp;&lt;b&gt;교착 상태&lt;/b&gt;가 발생할 수 있다. 교착 상태란 &lt;b&gt;일어나지 않을 사건을 기다리며 프로세스의 진행이 멈춰버리는 현상을 말한다.&amp;nbsp;&lt;/b&gt;교착 상태가 발생하는 조건은 크게 4가지가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상호 배제&lt;/b&gt; : 한 번에 하나의 프로세스만 해당 자원을 이용 가능했기 때문에 발생한다. 한 프로세스가 사용하는 자원을 다른 프로세스가 접근 불가능한 상호 배제 상황에서 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;점유와 대기(hold and wait)&lt;/b&gt;&amp;nbsp;: 한 프로세스가 어떤 자원을 할당받은 상태&lt;b&gt;(점유)&lt;/b&gt;에서 다른 자원 할당받기를 기다린다면&lt;b&gt;(대기)&lt;/b&gt; 교착 상태가 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비선점&amp;nbsp;&lt;/b&gt;: 비선점이라는 뜻은 결국 해당 자원을 이용하는 프로세스의 작업이 끝나야 그 자원을 쓸 수 있다는 뜻이다. 어떤 프로세스도 다른 프로세스의 자원을 강제로 빼앗지 못하는 경우 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;원형 대기 :&amp;nbsp;&lt;/b&gt;프로세스와 프로세스가 요청한 자원이 원을 이루는 형태일 때 일어날 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;교착 상태의 해결법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착 상태를 해결하는 방법은 크게 3가지 정도 있는데, 각각 살펴보자&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;교착 상태 예방 :&amp;nbsp;&lt;/b&gt;애초에 조건에 부합하지 않도록 자원을 분배해 예방한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;교착 상태를 발생시키는 원인 4가지 중 하나를 충족하지 못하게 하여 예방한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;교착 상태 회피 : &lt;/b&gt;교착 상태의 위험이 있을 때 자원을 할당하지 않는 방식으로 회피한다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기본적으로 교착 상태에 대해서 한정된 자원의 무분별한 할당으로 인해 발생하는 문제로 간주한다.&lt;/li&gt;
&lt;li&gt;대표적인 알고리즘으로는 은행원 알고리즘(banker's algorithm)이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;교착 상태 검출 후 회복 : &lt;/b&gt;교착 상태를 검출한 후에 회복한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;앞의 2가지는 발생 전에 막는 사전 조치였다면, 이 방식은 사후 조치에 해당한다.&lt;/li&gt;
&lt;li&gt;교착 상태가 검출되면, 프로세스를 &lt;b&gt;자원 선점을 통해 회복&lt;/b&gt;시키거나, 교착 상태에 있는 &lt;b&gt;프로세스를 강제 종료함&lt;/b&gt;으로써 회복시킬 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;figure id=&quot;og_1728098457520&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[OS] Process 동기화(세마포어,뮤텍스,모니터)&quot; data-og-description=&quot;동기화란 다중 스레드나 다중 프로세스 환경에서 공유 자원에 대한 접근을 조절하기 위해 사용되는 기술 임계 구역이란? 다른 프로세스와 공유하는 데이터에 접근하고 그 데이터를 갱신할 수 &quot; data-og-host=&quot;peonyf.tistory.com&quot; data-og-source-url=&quot;https://peonyf.tistory.com/entry/OS-Process-%EB%8F%99%EA%B8%B0%ED%99%94&quot; data-og-url=&quot;https://peonyf.tistory.com/entry/OS-Process-%EB%8F%99%EA%B8%B0%ED%99%94&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/vC5I7/hyXeiaiSQN/D1eKC1Qe2ZKpHYpk3UfL00/img.png?width=619&amp;amp;height=367&amp;amp;face=0_0_619_367,https://scrap.kakaocdn.net/dn/cnGRiX/hyXaEszALD/8kBVnRTJQpzyQzQUPDgSb1/img.png?width=619&amp;amp;height=367&amp;amp;face=0_0_619_367,https://scrap.kakaocdn.net/dn/KJJmX/hyXefYXwSQ/rdkThNeL4XGYJBoAdARybK/img.png?width=619&amp;amp;height=367&amp;amp;face=0_0_619_367&quot;&gt;&lt;a href=&quot;https://peonyf.tistory.com/entry/OS-Process-%EB%8F%99%EA%B8%B0%ED%99%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://peonyf.tistory.com/entry/OS-Process-%EB%8F%99%EA%B8%B0%ED%99%94&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/vC5I7/hyXeiaiSQN/D1eKC1Qe2ZKpHYpk3UfL00/img.png?width=619&amp;amp;height=367&amp;amp;face=0_0_619_367,https://scrap.kakaocdn.net/dn/cnGRiX/hyXaEszALD/8kBVnRTJQpzyQzQUPDgSb1/img.png?width=619&amp;amp;height=367&amp;amp;face=0_0_619_367,https://scrap.kakaocdn.net/dn/KJJmX/hyXefYXwSQ/rdkThNeL4XGYJBoAdARybK/img.png?width=619&amp;amp;height=367&amp;amp;face=0_0_619_367');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[OS] Process 동기화(세마포어,뮤텍스,모니터)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;동기화란 다중 스레드나 다중 프로세스 환경에서 공유 자원에 대한 접근을 조절하기 위해 사용되는 기술 임계 구역이란? 다른 프로세스와 공유하는 데이터에 접근하고 그 데이터를 갱신할 수&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;peonyf.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1728102886330&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[운영체제] 데드락(Deadlock, 교착 상태)이란?&quot; data-og-description=&quot;컴퓨터/IT/알고리즘 정리 블로그&quot; data-og-host=&quot;chanhuiseok.github.io&quot; data-og-source-url=&quot;https://chanhuiseok.github.io/posts/cs-2/#-%EB%8D%B0%EB%93%9C%EB%9D%BDdeadlock%EC%9D%98-%ED%95%B4%EA%B2%B0%EB%B2%95&quot; data-og-url=&quot;https://chanhuiseok.github.io/posts/cs-2/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://chanhuiseok.github.io/posts/cs-2/#-%EB%8D%B0%EB%93%9C%EB%9D%BDdeadlock%EC%9D%98-%ED%95%B4%EA%B2%B0%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://chanhuiseok.github.io/posts/cs-2/#-%EB%8D%B0%EB%93%9C%EB%9D%BDdeadlock%EC%9D%98-%ED%95%B4%EA%B2%B0%EB%B2%95&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[운영체제] 데드락(Deadlock, 교착 상태)이란?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터/IT/알고리즘 정리 블로그&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;chanhuiseok.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. CPU 스케줄링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제는 다양한 프로세스(스레드)에 CPU의 사용을 배분함으로써 CPU 자원을 관리한다고 설명했다. 이 배분방법이 바로 &lt;b&gt;CPU 스케줄링&lt;/b&gt;이다. CPU 스케줄링 알고리즘은 이런 스케줄링 절차를 의미하며, 이 알고리즘을 결정하고 수행하는 운영체제의 일부분을 CPU 스케줄러라고 한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;우선순위&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 프로세스는 CPU의 자원을 필요로 하기 때문에, 운영체제는 공정하고 합리적으로 자원을 할당해야 한다. 운영체제는 프로세스 별로 우선순위를 판단하여 PCB에 명시하고 우선순위가 높은 프로세스일수록 CPU의 자원을 더 빨리, 더 많이 할당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 어떤 프로세스에 우선순위를 높게 할당할까? 가장 대표적인 고려 요소는 CPU 활용률이다. 운영체제는 CPU 활용률을 높게 유지할 수 있도록 우선순위를 할당한다. CPU 활용률이란 전체 CPU 가동 시간 중 작업을 처리하는 시간의 비율을 의미한다. 운영체제는 높은 CPU 활용률을 유지하기 위해 기본적으로 입출력 작업이 많은 프로세스의 우선순위를 높게 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 프로세스들은 CPU와 입출력장치를 모두 사용해 실행과 대기 상태를 오간다. 이때 프로세스가 CPU를 이용하는 작업을 &lt;b&gt;CPU 버스트&lt;/b&gt;라고 하고, 입출력장치를 기다리는 작업을 &lt;b&gt;입출력 버스트&lt;/b&gt;라고 한다. 또한 &lt;b&gt;입출력 작업이 많은 프로세스는 입출력 집중 프로세스, CPU 작업이 많은 프로세스는 CPU 집중 프로세스라 불린다.&lt;br /&gt;&lt;/b&gt;만약 입출력 집중 프로세스와 CPU 집중 프로세스가 동시에 자원을 요청했다면,&lt;b&gt; 입출력 집중 프로세스를 가능한 빨리 실행시켜 끊임없이 입출력장치를 작동시킨 다음, CPU 집중 프로세스에 집중적으로 CPU를 할당하는 것이 더 합리적이다.&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스케줄링 큐&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제는 자원을 이용하고 싶은 프로세스들에게 줄을 서서 기다릴 것을 요구하는데, 이 줄은&amp;nbsp;&lt;b&gt;스케줄링 큐&lt;/b&gt;를 통해 구현된다. 운영체제가 관리하는 줄인 큐는 다양한 종류가 있지만 대표적으로&amp;nbsp;&lt;b&gt;준비 큐, 대기 큐&lt;/b&gt;에 대해서 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;준비 큐는 CPU를 이용하고 싶은 프로세스의 PCB가 서는 줄&lt;/b&gt;을 의미하고, &lt;b&gt;대기 큐는 대기 상태에 접어든 프로세스의 PCB가 서는 줄&lt;/b&gt;을 의미한다. 입출력 작업일 경우 주로 대기큐에서 완료 인터럽트를 기다리고, 준비 상태인 프로세스는 준비 큐의 마지막에 삽입되어 순서를 기다린다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;선점형 스케줄링과 비선점형 스케줄링&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케줄링은 프로세스의 실행이 끝나면 기본적으로 이루어진다. 그러나 어떤 프로세스가 작업이 끝나지 않았는데도 스케줄링 수행되는 대표적인 시점이 2개가 있다. 하나는&amp;nbsp;&lt;b&gt;실행 상태에서 입출력 작업을 위해 대기 상태로 전환&lt;/b&gt;될 때이고, 또 하나는 &lt;b&gt;실행 상태에서 타이머 인터럽트가 발생해 준비 상태로 변경&lt;/b&gt;될 때이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 위 상황 모두에서 수행되는 스케줄링 유형을 선점형 스케줄링이라고 하고, 전자에서는 수행되는 스케줄링 유형을 비선점형 스케줄링이라고 한다.&amp;nbsp;&lt;b&gt;선점형 스케줄링은 어떤 프로세스가 CPU를 할당받아 사용하고 있더라도 운영체제가 그걸 강제로 빼앗아 다른 프로세스에 할당할 수 있는 스케줄링을 의미한다.&lt;/b&gt; 따라서 타이머 인터럽트 기반 스케줄링은 선점형에 해당한다.&amp;nbsp;&lt;b&gt;비선점형 스케줄링은 그와 반대로 어떤 프로세스가 작업이 종료되거나 스스로 대기 상태에 접어들기 전에 끼어들 수 없는 스케줄링을 의미한다.&lt;/b&gt; 각각에는 다음과 같은 장단점이 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;선점형 스케줄링&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;비선점형 스케줄링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;더 급한 프로세스가 끼어들 수 있어 CPU 독점을 막을 수 있음.&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;문맥 교환 과정이 적어 오버헤드 발생은 적음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;문맥 교환 과정에서 오버헤드가 발생할 수 있음&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;당장 CPU를 사용해야하는 프로세스일지라도 이미 작업 중이라면 무한정 기다릴 수 밖에 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1 CPU 스케줄링 알고리즘&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 잠깐 설명했듯, 운영체제가 CPU를 프로세스에 배분하는 방법을 CPU 스케줄링 알고리즘이라고 했다. 그 알고리즘은 매우 다양하겠지만 대표적인 7가지 정도에 대해서만 알아보자.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 27.6744%;&quot;&gt;&lt;b&gt;선입 선처리 스케줄링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.3256%;&quot;&gt;준비 큐에 삽입된 순서대로 먼저 CPU를 요청한 프로세스부터 CPU를 할당하는 방식. 기다리는 시간이 매우 길어질 수 있고, 호위 효과() 문제가 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 27.6744%;&quot;&gt;&lt;b&gt;최단 작업 우선 스케줄링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.3256%;&quot;&gt;준비 큐에 삽입된 프로세스 중 CPU를 이용하는 시간이 짧은 프로세스부터 먼저 실행하는 스케줄링 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 27.6744%;&quot;&gt;&lt;b&gt;라운드 로빈 스케줄링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.3256%;&quot;&gt;선입 선처리 + 타임 슬라이스라는 개념이 더해진 스케줄링으로, 큐에 삽입된 순서대로 실행하되 타임 슬라이스만큼만 CPU를 이용하는 선점형 스케줄링이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 27.6744%;&quot;&gt;&lt;b&gt;최소 잔여 시간 우선 스케줄링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.3256%;&quot;&gt;최단 작업 우선 + 라운드 로빈을 합친 방식으로, 정해진 타임 슬라이스만큼 CPU를 이용하되, 남아 있는 작업시간이 가장 적은 프로세스를 다음으로 CPU를 이용할 프로세스로 정한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 27.6744%;&quot;&gt;&lt;b&gt;우선순위 스케줄링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.3256%;&quot;&gt;프로세스에 우선순위를 부여하고 우선순위 순으로 실행하는 방식이다. 다만 우선순위가 낮은 프로세스는 큐에 먼저 삽입되더라도 계속 지연되는 아사 현상 문제가 있다. 이를 위해 에이징 기법을 통해 오래 대기한 프로세스의 우선순위를 점차 올리는 방식으로 해결하기도 한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 27.6744%;&quot;&gt;&lt;b&gt;다단계 큐 스케줄링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.3256%;&quot;&gt;우선순위 스케줄링의 진화한 형태로 우선순위별로 여러 개의 준비 큐를 사용하는 방식이다. 다만 프로세스들이 큐 사이를 이동할 수 없기 때문에 아사 문제가 여전히 발생할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 27.6744%;&quot;&gt;&lt;b&gt;다단계 피드백 큐 스케줄링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.3256%;&quot;&gt;다단계 큐의 문제를 해결한 방식으로 프로세스들이 큐 사이를 이동할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 이론에서는 어떻게 CPU 스케줄링이 이루어지는 지에 대해서는 확인해 볼 수 있었다. 다만 실제 운영체제에서는 어떻게 이루어지고 있는지 리눅스 기반 운영체제에서 확인해 보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2 리눅스 CPU 스케줄링&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스에서는 상황에 따라 다양한 스케줄링 알고리즘이 사용될 수 있는데, 이는 스케줄링 정책을 보면 알 수 있다. 스케줄링 정책이란 새로운 프로세스를 언제 어떻게 선택하여 실행할지를 결정하기 위한 규칙의 집합으로, 리눅스에서는 크게 다음과 같은 5가지 스케줄링 정책을 사용한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 118px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 21.9767%; height: 21px;&quot;&gt;스케줄링 정책&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%; height: 21px;&quot;&gt;적용 상황&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 21.9767%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;SCHED_FIFO&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%; height: 34px;&quot; rowspan=&quot;2&quot;&gt;실시간성 프로세스에 적용되는 정책(높은 우선순위)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 21.9767%; height: 17px;&quot;&gt;&lt;span&gt;SCHED_RR&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 21.9767%; height: 21px;&quot;&gt;&lt;span&gt;SCHED_NORMAL&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%; height: 21px;&quot;&gt;일반적인 프로세스에 적용되는 정책&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 21.9767%; height: 21px;&quot;&gt;&lt;span&gt;SCHED_BATCH&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%; height: 21px;&quot;&gt;일반적인 프로세스만큼 자주 선점하지 않는 배치 작업에 적용되는 정책&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 21.9767%; height: 21px;&quot;&gt;&lt;span&gt;SCHED_IDLE&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%; height: 21px;&quot;&gt;우선순위 매우 낮은 프로세스에 적용되는 정책&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FIFO, RR은 RT라는 스케줄러에 의해 이뤄지는 스케줄링으로 실시간성이 강조된 프로세스에 적용되는 정책이다. NORMAL은 CFS라는 스케줄러에 의해 스케줄링이 이루어진다. 사실 자세한 내용은 조금 딥해지는 부분이 있기 때문에 더 깊게 학습하기를 윈 한다면 아래 참고 사항에서 추가적으로 확인하면 좋겠다. &lt;b&gt;핵심은 리눅스 CPU 스케줄링에서는 전통적인 CPU 스케줄링 방식과 조금 다르게 타임 슬라이스를 가중치에 따라 다르게 할당할 수 있다는 것만 인지하고 있자.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;figure id=&quot;og_1728104135098&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;CPU 스케줄링 알고리즘 요약정리&quot; data-og-description=&quot;CPU core가 하나라면 한 번에 하나의 프로세스만 실행 가능할 것이다. 이때 필요한 것이 CPU 스케줄링이다. 즉, CPU 스케줄링은 언제 어떤 프로세스에 CPU를 할당할지 결정하는 작업. 이 알고리즘은 CP&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@qq7455/CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9A%94%EC%95%BD%EC%A0%95%EB%A6%AC&quot; data-og-url=&quot;https://velog.io/@qq7455/CPU-스케줄링-알고리즘-요약정리&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLGyZ0/hyXd3Eefhu/0nPWHJdMDjgdrxPnESZko1/img.png?width=705&amp;amp;height=472&amp;amp;face=0_0_705_472,https://scrap.kakaocdn.net/dn/bV6rjt/hyXaHv2WHZ/ay2iDvj23RwUXMr5SYqQC1/img.png?width=705&amp;amp;height=472&amp;amp;face=0_0_705_472,https://scrap.kakaocdn.net/dn/b0Hhl8/hyXavCpgaa/6Q4jY3k7w6m3Igoxy6tEJk/img.png?width=790&amp;amp;height=482&amp;amp;face=0_0_790_482&quot;&gt;&lt;a href=&quot;https://velog.io/@qq7455/CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9A%94%EC%95%BD%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@qq7455/CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9A%94%EC%95%BD%EC%A0%95%EB%A6%AC&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLGyZ0/hyXd3Eefhu/0nPWHJdMDjgdrxPnESZko1/img.png?width=705&amp;amp;height=472&amp;amp;face=0_0_705_472,https://scrap.kakaocdn.net/dn/bV6rjt/hyXaHv2WHZ/ay2iDvj23RwUXMr5SYqQC1/img.png?width=705&amp;amp;height=472&amp;amp;face=0_0_705_472,https://scrap.kakaocdn.net/dn/b0Hhl8/hyXavCpgaa/6Q4jY3k7w6m3Igoxy6tEJk/img.png?width=790&amp;amp;height=482&amp;amp;face=0_0_790_482');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CPU 스케줄링 알고리즘 요약정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CPU core가 하나라면 한 번에 하나의 프로세스만 실행 가능할 것이다. 이때 필요한 것이 CPU 스케줄링이다. 즉, CPU 스케줄링은 언제 어떤 프로세스에 CPU를 할당할지 결정하는 작업. 이 알고리즘은 CP&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1728105048027&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;프로세스 스케줄링 (+리눅스에서의 스케줄링 예시)&quot; data-og-description=&quot;준비큐에서 기다리고 있는 프로세스 중 어떤 프로세스에게 자원을 할당할까? 에 대해 살펴보고자 합니다. 이를 위해 스케줄링의 목적과 고려사항에 대해 살펴보고 이를 고려하여 구현된 스케줄&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@youjung/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-9xcm3lp1#%EB%A6%AC%EB%88%85%EC%8A%A4%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://velog.io/@youjung/프로세스-스케줄링-9xcm3lp1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c6wx8f/hyXawVCcPG/ReCDN4VPKSQYiS5FLgkbMk/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500,https://scrap.kakaocdn.net/dn/b5Ty19/hyXeeMwtIY/vTKZMMoIdtROrIv0ghgwL0/img.png?width=2024&amp;amp;height=508&amp;amp;face=0_0_2024_508,https://scrap.kakaocdn.net/dn/cCDKrd/hyXaD05o2t/EZZkPT4A4cd5gVXX7YwrAk/img.png?width=1128&amp;amp;height=816&amp;amp;face=0_0_1128_816&quot;&gt;&lt;a href=&quot;https://velog.io/@youjung/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-9xcm3lp1#%EB%A6%AC%EB%88%85%EC%8A%A4%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@youjung/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-9xcm3lp1#%EB%A6%AC%EB%88%85%EC%8A%A4%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c6wx8f/hyXawVCcPG/ReCDN4VPKSQYiS5FLgkbMk/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500,https://scrap.kakaocdn.net/dn/b5Ty19/hyXeeMwtIY/vTKZMMoIdtROrIv0ghgwL0/img.png?width=2024&amp;amp;height=508&amp;amp;face=0_0_2024_508,https://scrap.kakaocdn.net/dn/cCDKrd/hyXaD05o2t/EZZkPT4A4cd5gVXX7YwrAk/img.png?width=1128&amp;amp;height=816&amp;amp;face=0_0_1128_816');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로세스 스케줄링 (+리눅스에서의 스케줄링 예시)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;준비큐에서 기다리고 있는 프로세스 중 어떤 프로세스에게 자원을 할당할까? 에 대해 살펴보고자 합니다. 이를 위해 스케줄링의 목적과 고려사항에 대해 살펴보고 이를 고려하여 구현된 스케줄&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1728105079739&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[운영체제] Linux의 CPU 스케줄링 (CFS 알고리즘)을 파보자!&quot; data-og-description=&quot;  해당 포스트는 운영체제 공룡책과 고건 교수님의 OLC 강의 등을 참고하여 작성되었습니다. Linux는 CFS(Completely Fair Scheduler)라는CPU 스케줄링 알고리즘을 사용해요!! CFS는 모든 프로세스가 공평&quot; data-og-host=&quot;hasensprung.tistory.com&quot; data-og-source-url=&quot;https://hasensprung.tistory.com/178&quot; data-og-url=&quot;https://hasensprung.tistory.com/178&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b8oDF6/hyXay6YSsQ/OKq6B0IicG8gkserupIKok/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cjE03f/hyXaADIE1l/wYJKl5kciI4FVwlLlVVe70/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/ko6fX/hyXaGYe9Sd/2SFLDNI5e5VSfn0Qil9ss0/img.png?width=1892&amp;amp;height=999&amp;amp;face=0_0_1892_999&quot;&gt;&lt;a href=&quot;https://hasensprung.tistory.com/178&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hasensprung.tistory.com/178&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b8oDF6/hyXay6YSsQ/OKq6B0IicG8gkserupIKok/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cjE03f/hyXaADIE1l/wYJKl5kciI4FVwlLlVVe70/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/ko6fX/hyXaGYe9Sd/2SFLDNI5e5VSfn0Qil9ss0/img.png?width=1892&amp;amp;height=999&amp;amp;face=0_0_1892_999');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[운영체제] Linux의 CPU 스케줄링 (CFS 알고리즘)을 파보자!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  해당 포스트는 운영체제 공룡책과 고건 교수님의 OLC 강의 등을 참고하여 작성되었습니다. Linux는 CFS(Completely Fair Scheduler)라는CPU 스케줄링 알고리즘을 사용해요!! CFS는 모든 프로세스가 공평&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hasensprung.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science</category>
      <category>cs</category>
      <category>교착 상태</category>
      <category>동기화</category>
      <category>스케줄링</category>
      <category>운영체제</category>
      <category>컴퓨터구조</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/104</guid>
      <comments>https://digitalagora.tistory.com/104#entry104comment</comments>
      <pubDate>Sat, 5 Oct 2024 14:12:09 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 3-1. 운영체제 - 전체 개요, 프로세스 &amp;amp; 스레드</title>
      <link>https://digitalagora.tistory.com/103</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&quot;이것이 취업을 위한 컴퓨터 과학이다 with CS 기술면접&quot; 책을 참고했습니다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 운영체제의 큰 그림&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스마트폰의 운영체제인 안드로이드나 iOS나 데스크톱 PC의 윈도우나 맥OS의 경우 형태는 다른 것 같지만 제공하는&amp;nbsp;&lt;b&gt;핵심적인 기능&lt;/b&gt;은 비슷하다. 이런 운영체제의 핵심적인 기능을 담당하는 부분을&amp;nbsp;&lt;b&gt;커널(Kernel)&lt;/b&gt;이라고 하는데, 별다른 언급이 없다면 이제부터 운영체제라고 설명하는 부분은 이 커널을 지칭한다고 이해하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제에는 2가지의 큰 핵심 기능이 있다. 하나는 자원을 할당하고 관리하는 역할이고, 다른 하나는 프로세스 및 스레드를 관리하는 역할이다. 이제 이 핵심 기능들을 차례대로 살펴보면서 전체적인 큰 그림을 그려보며 설명하겠다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2 운영체제의 역할&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제에서 설명하는 &lt;b&gt;자원이란 프로그램 실행에 마땅히 필요한 요소&lt;/b&gt;를 의미한다. 실행에 필요한 &lt;b&gt;데이터(소프트웨어)&lt;/b&gt;나 실행에 필요한 &lt;b&gt;부품(하드웨어)&lt;/b&gt;가 자원이 될 수 있다. 앞서 2장에서 정의하고 설명한 부분들이 핵심적인 자원이라고 할 수 있겠다.&lt;br /&gt;운영체제는 사용자가 직접 사용하고 있는 응용 프로그램을 대신해 CPU 등을 포함한 컴퓨터 부품에 접근하고 그 부품들이 효율적으로 사용되도록 관리한다. 또한 응용 프로그램들이 그 부품들을 효율적으로 할당받아 문제없이 실행되도록 자원을 할당한다. 아직 그게 어떤 건지 감은 안 오겠지만, 각각의 컴퓨터 부품들을 어떻게 효율적으로 관리하는지에 대해서 순차적으로 알아보며 더 접근하도록 하겠다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) CPU 관리 : CPU 스케쥴링&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 CPU와 메모리에 대해서 설명하면서 메모리에는 현재 실행 중인 프로그램이 다수 적재될 수 있다고 했었다. 하지만 그렇다고 해서 CPU가 이 모든 프로그램에 대해서 동시에 접근할 수는 없다. CPU는 한정적인 자원이기 때문에 CPU를 할당받아 사용하기 위해서는 다른 프로그램이 CPU 사용이 종료될 때까지 기다려야한다. 이때, &lt;b&gt;운영체제는 실행 중인 모든 프로그램들이 공정하고 합리적으로 CPU를 할당받을 수 있또록 CPU의 할당 순서와 사용 시간을 결정한다&lt;/b&gt;. 이것이 추후 학습할 CPU 스케줄링이라고 한다. 다음 시간에 확인할 내용이지만 핵심 내용만 정리하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 개념 : 우선순위, 스케줄링 큐, 선점형과 비선점형&lt;/li&gt;
&lt;li&gt;CPU 스케줄링 알고리즘&lt;/li&gt;
&lt;li&gt;리눅스 CPU 스케줄링&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 메모리 관리 : 가상 메모리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제는 새롭게 실행하는 프로그램을 메모리에 적재하고 종료된 프로그램을 적절히 삭제해야 한다. 이때 낭비되는 메모리 용량이 없도록 효율적으로 관리해야 할 노력도 필요한다. 오늘날 운영체제들 대부분은 이를 위해 &lt;b&gt;가상 메모리 기술&lt;/b&gt;을 활용한다. 이또한 추후 학습하겠지만 핵심은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 개념 : 물리 주소와 논리 주소&lt;/li&gt;
&lt;li&gt;메모리 할당&lt;/li&gt;
&lt;li&gt;페이징과 페이지 교체 알고리즘&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) 파일 / 디렉토리 관리 : 파일 시스템&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보조기억장치는 용량이 더 큰 만큼 효율적으로 관리할 필요가 있다. 아무렇게나 데이터를 저장한다면 어질러진 곳에서 물건을 찾듯 탐색 시간에 비효율적으로 많은 시간을 낭비하게 된다. 운영체제는 보조 기억 장치를 효율적으로 관리하기 위해&amp;nbsp;&lt;b&gt;파일 시스템&lt;/b&gt;을 사용한다. 파일 시스템은 크게 정보를 파일 및 폴더 단위로 접근하고 관리하도록 만들어진 운영체제의 내부 프로그램이다. 핵심은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일과 디렉토리&lt;/li&gt;
&lt;li&gt;파일 시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) 프로세스 및 스레드 관리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 실행 중인 프로그램이라고 지금까지 지칭했던 대상들은 &lt;b&gt;프로세스(process)&lt;/b&gt;라고 불린다. 그리고 프로세스의 내부적으로 프로세스를 이루는 실행의 단위를 &lt;b&gt;스레드(thread)&lt;/b&gt;라고 부른다. 메모리에는 여러 프로세스가 적재될 수 있고 이 프로세스에 대해서 운영체제는 자원을 할당해 스레드를 통해서 작업을 수행할 수 있다. 운영체제는 동시다발적으로 실행되는 프로세스와 스레드가 올바르게 처리되도록 실행 순서를 제어하고 그들이 요구하는 자원을 적절히 배분해야 한다. 어떻게 다뤄야 하는지 어떤 부분을 고려해야 하는지에 대한 자세한 내용은 아래에서 좀 더 다뤄보겠다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3 운영체제 학습 지도&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 설명했던 부분들을 핵심적인 대화 내용을 기준으로 작성한다면 다음과 같이 정리할 수 있겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1728023524161&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;운영체제
 |- 운영체제의 큰 그림
 	|- 커널
 	|- 시스템 콜
 |- 프로세스 및 스레드 관리
 	|- 프로세스와 스레드
 	|- 동기화와 교착 상태
 |- 자원 할당 및 관리
 	|- CPU 관리 : CPU 스케줄링
    	|- 기본 개념 : 우선순위, 스케줄링 큐, 선점형과 비선점형
        |- CPU 스케줄링 알고리즘
        |- 리눅스 CPU 스케줄링
    |- 메모리 관리 : 가상 메모리
    	|- 물리주소와 논리주소
        |- 메모리 할당
        |- 페이징과 페이지 교체 알고리즘
    |- 파일 / 디렉토리 관리 : 파일 시스템
    	|- 파일과 디렉토리
        |- 파일 시스템&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-4 시스템 콜과 이중 모드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 운영체제가 응용 프로그램들이 효율적으로 실행될 수 있도록 자원을 관리하고 할당한다는 말을 했지만, 운영체제 역시 프로그램이기 때문에 메모리에 적재되어야만 한다. 다만 일반적인 응용 프로그램과 달리 운영체제는&amp;nbsp;&lt;b&gt;커널 영역(kernel space)이라는 공간에 따로 적재되어 실행된다. &lt;/b&gt;메모리는 크게 커널 영역과 일반적인 응용 프로그램이 적재되는 &lt;b&gt;사용자 영역(user space)으로&lt;/b&gt;나뉘어 적재하며, 결국 운영체제의 기능을 제공받으려면 &lt;b&gt;커널 영역에 있는 운영체제 코드를 실행해야 한다.&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 응용 프로그램은 자원에 접근할 권한이나 기능이 없기 때문에 운영체제가 그 역할을 대행해서 수행한다. 이때 결국 응용 프로그램이 운영체제 코드를 실행해 자원에 접근해야 하는데, 이를 위해 응용 프로그램은 &lt;b&gt;시스템 콜(system call)&lt;/b&gt;을 호출해 실행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EcPgO/btsJV7fzCIY/gGNrB34JisKQPJtv2EBFrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EcPgO/btsJV7fzCIY/gGNrB34JisKQPJtv2EBFrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EcPgO/btsJV7fzCIY/gGNrB34JisKQPJtv2EBFrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEcPgO%2FbtsJV7fzCIY%2FgGNrB34JisKQPJtv2EBFrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;598&quot; height=&quot;305&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 콜은 운영체제의 서비스를 접근받기 위한 인터페이스로 호출 가능한 함수의 형태를 지닌다. 응용 프로그램이 운영체제에게 원하는 기능을 제공받고 싶다면 해당하는 시스템 콜을 호출함으로써 제공받을 수 있다. 순서는 아래와 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;소프트웨어 인터럽트 발생 -&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;CPU의 커널 모드 전환 &lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;-&amp;gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;운영체제 코드 실행 &lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;-&amp;gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;사용자 모드로 재전환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 위의 그림에서처럼 핵심은 소프트웨어 인터럽트, 사용자 모드, 커널 모드인데 각각 설명하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;소프트웨어 인터럽트&lt;/b&gt; : 운영체제에서 인터럽트를 발생시키는 특정 명령어들로, 자원에 접근하는 입출력 명령 같은 경우가 대표적이며 시스템 콜 역시 이 소프트웨어 인터럽트의 일종이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터럽트가 발생하면 일반적인 과정처럼 CPU는 현재 동작을 멈추고 백업한 뒤, 인터럽트를 처리하기 위한 코드를 실행한 뒤 해결되면 다시 사용자 영역의 코드를 재개한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CPU는 명령어를 실행하는 과정에서 사용자 영역과 커널 영역을 실행할 때의 모드를 나눠 설명하며, 이게&amp;nbsp;&lt;b&gt;사용자 모드, 커널 모드라고 한다. 그리고 이 2개의 모드로 구분해서 실행하는 걸 이중 모드라고 부른다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;사용자 모드 : 운영체제 서비스를 제공받을 수 없는 실행 모드로 커널 영역의 코드를 실행할 수 없다.&lt;/li&gt;
&lt;li&gt;커널 모드 : 운영체제 서비스를 제공받을 수 있는 실행 모드로 커널 영역의 코드를 실행할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 프로세스 &amp;amp; 스레드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터가 실행되는 순간부터 다양한 프로세스(프로그램)들이 메모리에 적재되어 실행된다. 프로세스는 사용자가 보이는 공간에서 상호작용하는&amp;nbsp;&lt;b&gt;foreground process&lt;/b&gt;나 보이지 않는 곳에서 실행되는&amp;nbsp;&lt;b&gt;background process&amp;nbsp;&lt;/b&gt;등이 있으며, 백그라운드 프로세스 중에는 사용자와 상호작용 없이 자신에게 주어진 임무만 수행하는&amp;nbsp;&lt;b&gt;데몬&lt;/b&gt;(윈도우에서는 service)도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스의 유형과 상관없이, 프로세스를 구성하는 메모리 내의 정보는 아래와 같은 구조에서 크게 벗어나지 않는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널 영역 : 프로세스 제어 블록(PCB)이 저장된다.&lt;/li&gt;
&lt;li&gt;사용자 영역 : 코드, 데이터, 힙, 스택 영역으로 나뉘어 저장된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 이해하기 쉬운 사용자 영역부터 차례대로 하나씩 간단히 알아보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;코드 영역&lt;/b&gt; : 읽기 전용의 CPU가 실행 가능한 명령어가 저장되는 공간으로 텍스트 영역이라고도 불린다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 영역&lt;/b&gt; : 프로그램이 실행되는 동안 유지할 데이터가 저장되는 공간이며, 여기에 저장되는 대표적 데이터는 &lt;b&gt;정적, 전역 변수&lt;/b&gt;가 대표적이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;힙 영역&lt;/b&gt; : 프로그램을 만드는 개발자가 직접 할당 가능한 저장공간이다. 다만 반환하지 않으면 &lt;b&gt;메모리 누수&lt;/b&gt; 같은 문제가 발생하기 때문에 주의가 필요하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스택 영역&lt;/b&gt; : 데이터 영역에 적재되는 변수와 달리 일시적으로 사용되는 일반 변수들이 저장되는 공간이다. 함수 종료 시 사라지는 &lt;b&gt;매개변수, 지역 변수, 함수 복귀 주소&lt;/b&gt; 같은 것이 대표적이다. 스택 영역에는 &lt;b&gt;스택 트레이스&lt;/b&gt; 형태의 함수 호출 정보가 저장되는데, 이는 &lt;b&gt;특정 시점에 스택 영역에 저장된 함수 호출 정보&lt;/b&gt;를 의미하며 문제의 발생 지점을 추적할 수 있어 디버깅 시 유용하게 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PCB와 문맥 교환&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 커널 영역에 PCB가 저장된다고 설명했었는데, PCB는 구체적으로 설명하면 운영체제가 다수의 프로세스를 관리하기 위해 프로세스를 식별할 수 있는 정보이다. PCB는 프로세스와 관련한 다양한 정보를 저장하는 구조체의 일종으로 새로운 프로세스가 메모리에 적재되면 생성되고 실행이 종료되면 폐기된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCB의 정보는 커널 내에서&amp;nbsp;&lt;b&gt;프로세스 테이블 형태&lt;/b&gt;로 관리되며 이는 실행 중인 PCB의 모음을 의미한다. PCB 내부의 정보는&amp;nbsp;약간씩 차이는 운영체제마다 존재하나 대표적인 정보는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프로세스 ID(PID)&lt;/b&gt; : 프로세스 식별 번호&lt;/li&gt;
&lt;li&gt;프로세스가 실행과정에서 &lt;b&gt;사용한 레지스터 값&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;현재 프로세스의 상태&lt;/b&gt;를 나타내는 정보&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU 스케줄링(우선순위) 정보&lt;/b&gt; : 프로세스가 언제 어떻게 CPU를 할당받는지 나타내는 정보&lt;/li&gt;
&lt;li&gt;프로세스의 &lt;b&gt;메모리 상 적재 위치&lt;/b&gt;가 표시된 메모리 관련 정보&lt;/li&gt;
&lt;li&gt;프로세스가 &lt;b&gt;사용한 파일 및 입출력 장치&lt;/b&gt; 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스가 실행된다는 것은 운영체제의 CPU의 자원을 할당받았다는 말과 같다. 프로세스의 CPU 사용 시간은 타이머 인터럽트에 의해 제어된다. &lt;b&gt;타이머 인터럽트&lt;/b&gt;는 시간이 끝났음을 알리는 인터럽트로 &lt;b&gt;타임아웃 인터럽트&lt;/b&gt;라고 불리기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스는 타이머 인터럽트 발생 전에 지금까지의 중간 정보를 백업해야 다음 차례가 되었을 때 이어서 업무를 재개할 수 있다. 여기서 백업 대상이 되는 중간 정보, &lt;b&gt;재개를 위해 기억해야 할 정보를 문맥(context)&lt;/b&gt;라고 한다. 이 문맥은 해당 프로세스의 PCB에 명시되며 타이머 인터럽트 발생 시에 이 부분에 백업하고 다음 실행할 프로세스의 문맥을 복구하며 자연스레 바뀌게 된다.&lt;br /&gt;이처럼 기존 프로세스의 문맥을 백업하고 새 프로세스의 문맥을 복구하는 일련의 과정을 &lt;b&gt;문맥 교환(context switch)&lt;/b&gt;라고 부른다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프로세스의 상태&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스는 여러 상태를 거치며 실행된다. 운영체제는 PCB를 통해 이런 상태를 인식하고 관리한다. 운영체제 별로 상태를 표현하는 방식은 대동소이하며 다음과 같은 그림으로 표현이 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1009&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caz7Tr/btsJWgKj5qy/LQyXwrGHQ4Vu24K3as4z6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caz7Tr/btsJWgKj5qy/LQyXwrGHQ4Vu24K3as4z6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caz7Tr/btsJWgKj5qy/LQyXwrGHQ4Vu24K3as4z6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcaz7Tr%2FbtsJWgKj5qy%2FLQyXwrGHQ4Vu24K3as4z6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1009&quot; height=&quot;520&quot; data-origin-width=&quot;1009&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성(new) : 생성 중인 상태로, 메모리에 적재되어 PCB를 할당받은 상태이다.&lt;/li&gt;
&lt;li&gt;준비(ready) : 당장 할당받아 실행 가능한 상태지만 차례가 아니라 기다리고 있는 상태를 의미한다. CPU를 할당받아 실행 상태로 전환되는 것을 디스패치(dispatch)라고 한다.&lt;/li&gt;
&lt;li&gt;실행(running) : 실제 CPU를 할당받아 실행 중인 상태로 정해진 시간 동안만 실행 가능하며, 할당된 시간을 모두 사용하면 준비 상태로 돌아가게 된다. 다만 실행 도중 입출력 장치를 사용하게 된다면 입출력 신호를 발생하고 작업이 끝날 때까지 대기 상태가 된다.&lt;/li&gt;
&lt;li&gt;대기(blocked) : 프로세스가 입출력 작업을 요청하거나 확보할 수 없는 자원을 요청하는 등 곧장 실행이 불가능한 조건에 놓이는 경우 대기 상태가 된다. 대기 상태는 다양한 경우가 있지만 입출력 작업이 대표적이다. 다시 실행 가능한 상태가 되면 준비 상태로 전환되어 CPU 할당을 기다린다.&lt;/li&gt;
&lt;li&gt;종료(terminated) : 모든 작업이 종료되어 운영체제가 PCB와 메모리를 정리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;멀티프로세스와 멀티스레드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 프로세스를 구성하는 코드를 동시에 실행하려면 어떻게 해야 될까? 한 가지는 같은 프로그램에 대해서 서로 다른 여러 프로세스를 실행하는 방법이 있겠다. 대표적으로 웹 브라우저의 탭 기능이 있으며, 이와 같이 동시에 여러 프로세스가 동시에 실행되는 것을 &lt;b&gt;멀티프로세스&lt;/b&gt;라고 부른다.&amp;nbsp;코드를 동시에 실행하는 또 다른 방법은 여러 스레드를 이용하는 방법이 있는데, 이를 &lt;b&gt;멀티스레드&lt;/b&gt;라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티프로세스와 멀티스레드의 가장 큰 차이점은 &lt;span style=&quot;background-color: #f3c000;&quot;&gt;&lt;b&gt;자원의 공유 여부&lt;/b&gt;&lt;/span&gt;에 있다. 멀티프로세스는 자원을 서로 공유하지 않고 독립적으로 실행되는 반면, 멀티스레드의 경우 하나의 프로세스의 자원을 공유한다. 같은 자원을 공유하기 때문에 쉽게 협력하고통신 가능하지만, 한 스레드의 문제가 다른 스레드를 넘어 전체 프로세스의 영향을 끼칠 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프로세스 간 통신&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 멀티프로세스에 대해서 이야기할 때, 기본적으로 자원을 공유하지 않는다고 했었다. 하지만 그럼에도 서로 자원을 공유하고 데이터를 주고받을 수 있는 방법이 있는데 이를 &lt;b&gt;프로세스 간 통신(IPC : inter-Process Communication)&lt;/b&gt;이라고 부른다. IPC는 크게 &lt;b&gt;공유 메모리&lt;/b&gt;와 &lt;b&gt;메시지 전달 방식&lt;/b&gt;이 있다. 공유 메모리는 데이터를 주고받는 프로세스가 공통적으로 사용할 메모리 영역을 두는 방식이고, 메시지 전달은 프로세스 간에 주고받을 데이터를 메시지 형태로 주고받는 방법을 의미한다. 각각의 특징은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유 메모리 기반 IPC&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마치 자신의 메모리 영역을 읽고 쓰는 것처럼 통신한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널 영역을 거치지 않는 경우가 많다&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;각 프로세스가 각자의 메모리 영역을 읽고 쓰는 것 뿐이므로 &lt;b&gt;속도가 메시지 전달 방식보다 빠르다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;동시에 공유 메모리 영역을 읽고 쓰면 &lt;b&gt;데이터 일관성이 훼손될 문제&lt;/b&gt;가 있다. 이를 레이스 컨디션이라고 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지 전달 기반 IPC&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지를 &lt;b&gt;보낼 수단과 받는 수단&lt;/b&gt;이 명확하게 구분되어 있다.&lt;/li&gt;
&lt;li&gt;커널의 도움을 적극적으로 받기 때문에 &lt;b&gt;레이스 컨디션 문제가 적다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;커널을 통해 송수신되므로 &lt;b&gt;공유 메모리보다는 통신 속도가 늦다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;대표적인 수단으로는 &lt;b&gt;파이프, 시그널, 소켓, 원격 프로시저 호출&lt;/b&gt; 등이 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이프는 단방향 프로세스 간 통신 도구를 말한다.&lt;/li&gt;
&lt;li&gt;시그널은 프로세스에게 특정 이벤트가 발생했음을 알리는 비동기 신호를 의미한다. 시그널이 발생하면 프로세스는 인터럽트 처리과정과 유사하게 시그널 처리를 위한 시그널 핸들러를 실행한 뒤, 해결하고 나서 실행을 재개한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;figure id=&quot;og_1728027918519&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot; &amp;zwj;  &amp;zwj;완전히 정복하는 프로세스 vs 스레드 개념&quot; data-og-description=&quot;한눈에 이해하는 프로세스 &amp;amp; 스레드 개념 전공 지식 없이 컴퓨터의 프로그램을 이용하는데는 문제 없어 왔지만 소프트웨어를 개발하는 사람으로서 컴퓨터 실행 내부 요소를 따져보게 될때, 아&quot; data-og-host=&quot;inpa.tistory.com&quot; data-og-source-url=&quot;https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%E2%9A%94%EF%B8%8F-%EC%93%B0%EB%A0%88%EB%93%9C-%EC%B0%A8%EC%9D%B4&quot; data-og-url=&quot;https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%E2%9A%94%EF%B8%8F-%EC%93%B0%EB%A0%88%EB%93%9C-%EC%B0%A8%EC%9D%B4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Pq20O/hyXd35bEAO/BApjNN13gKxHH4J0OEMor0/img.png?width=800&amp;amp;height=352&amp;amp;face=0_0_800_352,https://scrap.kakaocdn.net/dn/bauNdn/hyXef5CVc1/Ig3At2Jjs40NPvf7SVro2K/img.png?width=800&amp;amp;height=352&amp;amp;face=0_0_800_352,https://scrap.kakaocdn.net/dn/gB8De/hyXegcmT6e/qk5lazj6DEo1xwhNeKFVuk/img.png?width=1403&amp;amp;height=618&amp;amp;face=0_0_1403_618&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%E2%9A%94%EF%B8%8F-%EC%93%B0%EB%A0%88%EB%93%9C-%EC%B0%A8%EC%9D%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%E2%9A%94%EF%B8%8F-%EC%93%B0%EB%A0%88%EB%93%9C-%EC%B0%A8%EC%9D%B4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Pq20O/hyXd35bEAO/BApjNN13gKxHH4J0OEMor0/img.png?width=800&amp;amp;height=352&amp;amp;face=0_0_800_352,https://scrap.kakaocdn.net/dn/bauNdn/hyXef5CVc1/Ig3At2Jjs40NPvf7SVro2K/img.png?width=800&amp;amp;height=352&amp;amp;face=0_0_800_352,https://scrap.kakaocdn.net/dn/gB8De/hyXegcmT6e/qk5lazj6DEo1xwhNeKFVuk/img.png?width=1403&amp;amp;height=618&amp;amp;face=0_0_1403_618');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt; &amp;zwj;  &amp;zwj;완전히 정복하는 프로세스 vs 스레드 개념&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;한눈에 이해하는 프로세스 &amp;amp; 스레드 개념 전공 지식 없이 컴퓨터의 프로그램을 이용하는데는 문제 없어 왔지만 소프트웨어를 개발하는 사람으로서 컴퓨터 실행 내부 요소를 따져보게 될때, 아&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inpa.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science</category>
      <category>스레드</category>
      <category>운영체제</category>
      <category>컴퓨터 구조</category>
      <category>프로세스</category>
      <author>solitude12</author>
      <guid isPermaLink="true">https://digitalagora.tistory.com/103</guid>
      <comments>https://digitalagora.tistory.com/103#entry103comment</comments>
      <pubDate>Fri, 4 Oct 2024 16:45:28 +0900</pubDate>
    </item>
  </channel>
</rss>