<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sohyeonbak_oly.log</title>
        <link>https://velog.io/</link>
        <description>정리하고 기억하는 곳</description>
        <lastBuildDate>Tue, 03 Jan 2023 12:02:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>sohyeonbak_oly.log</title>
            <url>https://images.velog.io/images/sohyeonbak_oly/profile/293b4be4-55d1-4726-b3cf-e1620f707ac2/IMG_5347.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. sohyeonbak_oly.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sohyeonbak_oly" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[JavaScript '비동기 처리'란?]]></title>
            <link>https://velog.io/@sohyeonbak_oly/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC%EB%9E%80</link>
            <guid>https://velog.io/@sohyeonbak_oly/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC%EB%9E%80</guid>
            <pubDate>Tue, 03 Jan 2023 12:02:54 GMT</pubDate>
            <description><![CDATA[<h1 id="callback-function">Callback Function</h1>
<ul>
<li>특정 동작을 실행할 때 실행하는 함수</li>
<li>비동기 동작에서</li>
<li>모든 콜백 함수가 비동기 처리를 위하는 것은 아님(그러나 비동기 처리를 위하는 경우가 많음)<ul>
<li>setTimeout, setInterval</li>
<li>이벤트 처리</li>
<li>node.js 파일 입출력 API, 네트워크 API</li>
</ul>
</li>
</ul>
<h2 id="callback-hell">Callback Hell</h2>
<ul>
<li>여러 비동기 처리에 콜백 함수를 사용할 때 발생</li>
<li>코드가 직관적으로 이해하기 어려울 정도로 복잡해짐</li>
</ul>
<h1 id="promise-object">Promise Object</h1>
<ul>
<li>비동기 동작의 처리를 담당하는 <strong>객체</strong></li>
<li>new Promise 객체에 전달되는 함수 <code>executor</code>(실행자, 실행 함수)는 <code>new Promise</code>가 만들어질 때 자동으로 실행된다.<ul>
<li>자동으로 실행되는 <code>executor</code>에서 원하는 일이 처리된다.</li>
<li>executor에서 인자로 넘겨준 <code>콜백(resolve, reject)</code> 중 하나는 반드시 호출되어야 한다.</li>
</ul>
</li>
<li><code>이행(fulfilled)</code>, <code>거부(rejected)</code>, <code>대기(pending)</code> 상태를 통해 비동기 동작 처리<ul>
<li>이행(fulfilled), 거부(rejected)의 상태는 <strong>&#39;처리된(settled) 프라미스&#39;</strong></li>
<li>동기식 함수의 성공(=이행), 실패(=거부)에 추가된 한가지 상태는 <strong>&#39;대기(pending) 상태 프라미스&#39;</strong></li>
</ul>
</li>
<li><code>Promise.resolve()</code>로 성공한 객체 생성<ul>
<li>일이 성공적으로 끝난 경우 그 결과를 나타내는 value와 함께 호출<strong>(fulfilled promise-약속이 이행된 프라미스)</strong>
<code>javascript
  Promise.resolve(100);
  new Promise(resolve =&gt; resolve(100));</code></li>
</ul>
</li>
<li><code>Promise.reject()</code>로 실패한 객체 생성<ul>
<li>에러 발생 시 에러 객체를 나타내는 error와 함께 호출
<code>javascript
Promise.reject(&#39;error!&#39;);
  new Promise((_, reject) =&gt; reject(&#39;error!&#39;));</code></li>
</ul>
</li>
<li>처리가 완료된 프라미스에 resolve나 reject를 또 호출하면 무시된다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/dfe1957a-65ed-4062-9891-c6b778469e68/image.png" alt=""></p>
<h2 id="then성공시콜백">.then(성공시콜백)</h2>
<ul>
<li><p><code>.then</code>의 첫번째 인수는 프라미스가 이행(fulfilled)되었을 때 실행되는 함수이고, 이곳에서 실행 결과를 받는다.</p>
</li>
<li><p><code>.then</code>의 두번째 인수는 프라미스가 거부(rejected)되었을 때 실행되는 함수이고, 이곳에서 에러를 받는다. </p>
<pre><code class="language-javascript">promise.then(
    result =&gt; alert(result), // 1초 후 &quot;완료!&quot;를 출력
    error =&gt; alert(error) // 실행되지 않음
);</code></pre>
</li>
<li><p>콜백에서 반환된 <code>promise</code> 객체는 다음 <code>then</code>에서 처리</p>
<pre><code class="language-javascript">fetch(&#39;http://example.com/movies.json&#39;)
  .then((res) =&gt; res.json()) //promise object type
  .then((data) =&gt; console.log(data)) // object type
  .catch(err =&gt; console.err(err));</code></pre>
</li>
<li><p><code>promise</code> 객체가 아닌 값을 반환할 때는 성공한 <code>promise</code>처럼 생각</p>
<pre><code class="language-javascript">fetch(&#39;http://example.com/movies.json&#39;)
  .then((res) =&gt; res.status) //object type
  .then((data) =&gt; console.log(data))
  .catch(err =&gt; console.err(err));</code></pre>
</li>
<li><p>&quot;성공시콜백&quot;이 함수가 아닐 때 → 받은 값 그대로 취급</p>
<pre><code class="language-javascript">fetch(&#39;http://example.com/movies.json&#39;)
  .then(value =&gt; value)
  .then((data) =&gt; console.log(data));
</code></pre>
</li>
</ul>
<p>fetch(&#39;<a href="http://example.com/movies.json&#39;">http://example.com/movies.json&#39;</a>)
    .then(&#39;data&#39;)
    .then((data) =&gt; console.log(data));</p>
<pre><code>

## .catch(실패시콜백)
- ```.then(undefined, 실패시콜백)```의 단축 문법
- ```.catch``` 후에도 ```.then```을 계속 사용할 수 있다.
    * 위 아래 코드는 같은 동작을 한다.
```javascript
    new Promise((resolve, reject) =&gt; {
        console.log(&quot;시작&quot;)
        resolve();
        console.log(&quot;시작2&quot;)
    })
    .then(() =&gt; {
        throw new Error(&quot;실패!&quot;)
        console.log(&quot;&quot;)
    })
    .catch(() =&gt; {
        console.error(&quot;실패시 실행&quot;)
    })
    .then(() =&gt; {
        console.log(&quot;이건 꼭 실행하세요.&quot;)
    })</code></pre><pre><code class="language-javascript">    new Promise((resolve, reject) =&gt; {
        console.log(&quot;시작&quot;)
        resolve();
        console.log(&quot;시작2&quot;)
    })
    .then(() =&gt; {
        throw new Error(&quot;실패!&quot;)
        console.log(&quot;&quot;)
    })
    .then(undefined, () =&gt; {
        console.error(&quot;실패시 실행&quot;)
    })
    .then(() =&gt; {
        console.log(&quot;이건 꼭 실행하세요.&quot;)
    })</code></pre>
<h2 id="finally결정시콜백">.finally(결정시콜백)</h2>
<ul>
<li><code>.then(결정시콜백)</code>과 비슷한 느낌</li>
<li>결정시콜백에서 반환되는 값은 무시된다.</li>
<li>쓸모가 없어진 로딩 인디케이터를 멈추는 경우와 같이 결과가 어떻든 마무리가 필요할 때 사용된다. <ul>
<li><code>finally</code>에서는 프라미스가 이행되었는지, 거부되었는지 알 수 없다.</li>
<li><code>finally</code>는 자동으로 다음 핸들러의 결과와 에러를 전달한다.<pre><code class="language-javascript">new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; resolve(&quot;결과&quot;), 2000)
})
.finally(() =&gt; alert(&quot;프라미스가 준비되었습니다.&quot;))
.then(result =&gt; alert(result));// &lt;-- .then에서 result를 다룰 수 있음</code></pre>
</li>
</ul>
</li>
</ul>
<pre><code class="language-javascript">new Promise((resolve, reject) =&gt; {
          throw new Error(&quot;에러 발생!&quot;);
    })
      .finally(() =&gt; alert(&quot;프라미스가 준비되었습니다.&quot;))
      .catch(err =&gt; alert(err)); // &lt;-- .catch에서 에러 객체를 다룰 수 있음</code></pre>
<h2 id="thenable">Thenable</h2>
<ul>
<li><code>.then</code>만 있으면 나머지 두 개는 구현/대체 가능</li>
<li>호환성을 위해 객체에 <code>.then()</code>이 있으면 <code>promise</code> 처리가 가능</li>
</ul>
<h2 id="promise-다중-처리">Promise 다중 처리</h2>
<ul>
<li>배열(iterable)로 전달받은 promise 객체가 있을 때<ul>
<li><code>promise.any</code>: 가장 먼저 이행된 값을 이행, 모두 실패하면 실패</li>
<li><code>promise.all</code>: 모두 이행되면 값 배열로 전달하며 이행, 하나라도 실패하면 실패</li>
<li><code>promise.race</code>: 가장 먼저 결정된 값에 따라 결정</li>
<li><code>promise.allSettled</code>: 모두 결정되면 결과 객체 배열이 전달되며 이행<ul>
<li><code>.status</code>: &quot;fulfilled&quot; 또는 &quot;rejected&quot;</li>
<li><code>.value</code>: &quot;fulfilled&quot;된 경우에만 존재</li>
<li><code>.reason</code>: &quot;rejected&quot;된 경우에만 존재</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="마이크로태스크-큐">마이크로태스크 큐</h2>
<ul>
<li>프라미스 핸들러 <code>.then/.catch/.finally</code>는 항상 비동기로 실행된다.<ul>
<li>콘솔 창에 &quot;코드 종료&quot;, &quot;프라미스 성공!&quot; 순서로 찍힌다.</li>
</ul>
</li>
</ul>
<pre><code class="language-javascript">    let promise = Promise.resolve();
        promise.then(() =&gt; alert(&quot;프라미스 성공!&quot;));
        alert(&quot;코드 종료&quot;);</code></pre>
<ul>
<li>마이크로태스크 큐는 먼저 들어온 작업을 먼저 실행한다<strong>(FIFO)</strong></li>
<li>실행할 것이 아무것도 남아있지 않을 때만 마이크로태스크 큐에 있는 작업이 실행된다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/c0883fe3-5572-42b0-bfd5-f1e85811d3c9/image.png" alt=""></p>
<ul>
<li>프라미스 핸들러는 항상 내부 큐를 통과하게 된다.</li>
<li>모든 프라미스 동작은 마이크로태스크 큐라 불리는 내부 프라미스 잡(promise job) 큐에 들어가 처리되기 때문에 프라미스 핸들링은 항상 비동기로 처리된다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/90753c1a-f3d1-4700-8678-12cb420b29a3/image.gif" alt=""></p>
<h1 id="async-await">Async-Await</h1>
<h2 id="async-함수">Async 함수</h2>
<ul>
<li><p>항상 <code>Promise</code>를 반환하는 함수</p>
<ul>
<li><p><code>async</code>가 앞에 붙는 함수는 항상 프라미스를 반환한다.</p>
</li>
<li><p>프라미스가 아닌 값을 반환해도 이행 상태의 프라미스(resolved promise)로 값을 감싸 이행된 프라미스가 반환된다.</p>
<pre><code class="language-javascript">  async function f() {
        return 1;
  }

  f().then(alert); // 1</code></pre>
<ul>
<li><p>명시적으로 프라미스 반환도 가능</p>
<pre><code class="language-javascript">async function f() {
     return Promise.resolve(1);
}

f().then(alert); // 1</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p>또는 <code>await</code> 연산자를 내부에 사용하는 함수</p>
</li>
<li><p>항상 <code>Promise</code>를 반환해야하는 것과 <code>await</code> 연산자를 내부에 쓸 필요가 없으면 async를 사용할 필요가 없다.</p>
</li>
</ul>
<h2 id="await-연산자">Await 연산자</h2>
<ul>
<li><p><code>Promise</code> 상태가 결정될 때까지 대기</p>
<pre><code class="language-javascript">  async function one() {
      return new Promise(resolve =&gt; setTimeout(() =&gt; resolve(1230)))
          .then(v =&gt; v+4)
          .catch(e =&gt; console.error(e));
  }
  const num = await one();
  console.log(num) // 1234 출력</code></pre>
</li>
<li><p>사실 Thenable을 실행하는데, 그 외의 값도 가능</p>
<pre><code class="language-javascript">  const num = await {
      then(fulfill) { fulfill(123) }
  }
  console.log(num)
  console.log(await &quot;hello&quot;);</code></pre>
</li>
<li><p><code>await</code>은 <code>promise.then</code> 보다 더 세련되게 프라미스의 결과 값을 얻을 수 있게 해준다.</p>
<ul>
<li>비동기 함수의 실행 순서를 마치 동기실처럼 제어</li>
</ul>
</li>
<li><p>에러 처리는 <code>try/catch</code>를 사용한다.</p>
</li>
<li><p>await을 만나면 실행을 중단하고 ````microtask queue```에 넣는다.</p>
<ul>
<li>비동기로 동작한다는 뜻</li>
</ul>
</li>
<li><p>async 함수 내부나 모듈의 <strong>top-level</strong>에서만 사용 가능</p>
</li>
</ul>
<blockquote>
<p><strong>async/await과 promise.then/.catch</strong>
    - async/await을 사용하면 await이 대기처리를 해주기 때문에 then이 거의 사용되지 않는다.
    - 또한 .catch보다 try/catch를 사용할 수 있게 된다.
    - 그렇지만 문법적 제약(함수안에서 await을 사용할 수 있는) 때문에 .then/.catch를 추가해 처리하지 못한 에러나 최종 결과를 도출 할 수 있다.</p>
</blockquote>
<blockquote>
<p><strong>async/await는 Promise.all과도 함께 쓸 수 있다.</strong></p>
</blockquote>
<h1 id="비동기-처리-유의사항">비동기 처리 유의사항</h1>
<ul>
<li>비동기 함수 간에는 실행 순서 보장 안되는 게 기본</li>
<li>async 함수 내에서는 await을 사용해 실행 순서 보장</li>
<li>동시 처리가 필요하다면 promise 정적 함수 활용</li>
<li>비동기 처리가 필요하면 async/await을 최대로 활용</li>
<li>DOM 이벤트 핸들러로 async 함수를 사용할 수 있다.</li>
<li>비동기는 성능과 관련있다.<ul>
<li>네트워크 처리, 파일 입출력하는 기간동안 작업을 위임해 진행할 수 있게 도와준다.</li>
</ul>
</li>
<li>기능별 async 함수 만들고, 실행순서 보장 할 수 있는 모듈을 만드는게 좋다.</li>
</ul>
<h3 id="출처">출처</h3>
<p>[패스트캠퍼스] &lt;개발 세미나 : D-day Vol. 2&gt; 자바스크립트 비동기 처리
<a href="https://ko.javascript.info/async">모던 자바스크립트 - 프라미스와 async, await</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS 기초] 운영체제와 정보기술]]></title>
            <link>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%A0%95%EB%B3%B4%EA%B8%B0%EC%88%A0-g8h4bu3v</link>
            <guid>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%A0%95%EB%B3%B4%EA%B8%B0%EC%88%A0-g8h4bu3v</guid>
            <pubDate>Thu, 29 Sep 2022 23:44:53 GMT</pubDate>
            <description><![CDATA[<h1 id="09-디스크-관리">09. 디스크 관리</h1>
<blockquote>
<p><strong>디스크</strong>
컴퓨터 시스템의 대표적인 2차 저장장치.
메모리는 휘발성 저장장치로 전원이 나가면 그 내용이 모두 사라진다.
영구히 보관하기 위해서는 디스크와 같은 2차 저장장치를 이용해야한다.</p>
</blockquote>
<h2 id="디스크-구조">디스크 구조</h2>
<h4 id="논리블록">논리블록</h4>
<p>: 디스크 외부에서는 디스크를 일정한 크기의 저장공간들로 이루어진 1차원 배열처럼 취급하는데 이 저장공간을 논리블록이라고 한다.</p>
<ul>
<li>디스크에 데이터가 저장될 때에는 논리블록 단위로 저장</li>
<li>디스크 외부로 입출력이 일어날 때에도 논리블록 단위로 전송</li>
<li>논리블록에 저장된 데이터에 접근하기 위해서는 해당 블록의 인덱스 번호를 디스크에 전달</li>
<li>논리블록이 저장된 디스크 내의 물리적 위치를 <strong>섹터</strong></li>
<li>논리블록 하나가 섹터 하나와 1대 1로 매칭</li>
</ul>
<h4 id="디스크의-물리적구조">디스크의 물리적구조</h4>
<p>: 마그네틱 원판으로 구성</p>
<ul>
<li>원판은 트랙으로 구성</li>
<li>트랙은 섹터로 나뉨
: 섹터에 최소한의 단위 정보가 저장</li>
<li>여러개의 원판에서 상대적 위치가 동일한 트랙들의 집합을 <strong>실린더</strong>
: 디스크에 데이터를 읽고 쓰기 위해 암이 해당 섹터가 위치한 실린더로 이동 후 원판이 회전하여 디스크 헤드가 저장된 섹터 위치에 도달</li>
</ul>
<h2 id="디스크-스케줄링">디스크 스케줄링</h2>
<h4 id="디스크-접근시간">디스크 접근시간</h4>
<ul>
<li>탐색시간
: 디스크 헤드를 해당 실린더 위치로 이동시키는데 걸리는 시간<ul>
<li>접근하려는 데이터가 원판의 안쪽에 있는지 바깥쪽에 있는지에 따라 헤드를 움직이는데 걸리는 시간이다.</li>
</ul>
</li>
<li>회전지연시간
: 디스크가 회전해서 읽고 쓰려는 섹터가 헤드 위치에 도달하기까지 걸리는 시간</li>
<li>전송시간
: 해당 섹터가 헤드 위치에 도달한 후 데이터를 실제로 섹터에 읽고 쓰는데 소요되는 시간</li>
</ul>
<h4 id="디스크-입출력의-효율을-높이기-위한-방법">디스크 입출력의 효율을 높이기 위한 방법</h4>
<ul>
<li>디스크 입출력에 소요되는 접근시간 최소화</li>
<li>회전지연시간과 전송시간은 상대적인 수치가 작고 운영체제 입장에서 통제하기 힘들다.
→ 탐색시간을 줄여야 하는데 이를 위해 헤드의 움직임을 최소화하는 스케줄링 작업을 한다.<h4 id="디스크-스케줄링-1">디스크 스케줄링</h4>
: 효율적인 디스크 입출력을 위해 여러 섹터들에 대한 입출력 요청이 들어왔을 때 이들을 어떠한 순서로 처리할 것인지 결정하는 매커니즘
→ 디스크 헤드의 이동거리를 줄이는 것!</li>
</ul>
<h3 id="fcfs-스케줄링">FCFS 스케줄링</h3>
<p>: 디스크에 먼저 들어온 요청을 먼저 처리하는 방식</p>
<ul>
<li>합리적인 것처럼 보이지만 효율성은 매우 낮음 (디스크 헤드가 움직이면서 서비스를 하기 때문)</li>
<li>FCFS 스케줄링이 적용되는 디스크에서 최악의 경우 입출력 요청이 디스크의 한쪽 끝과 반대쪽 끝에 번갈아 도착하면 헤드는 디스크를 계속 왕복해 일을 처리해야해서 탐색시간이 매우 비효율적</li>
</ul>
<h3 id="sstf-스케줄링">SSTF 스케줄링</h3>
<p>: 헤드의 현재 위치로부터 가장 가까운 위치에 있는 요청을 제일 먼저 처리하는 알고리즘</p>
<ul>
<li>SSTF는 헤드의 이동거리를 줄여 디스크 입출력의 효율성을 증가 시키지만 자칫 기아현상 발생</li>
<li>헤드위치로부터 가까운 곳에서 지속적인 요청이 들어올 경우 헤드 위치에서 멀리 떨어진 곳의요청은 무한히 기다려야 하는 문제 발생</li>
</ul>
<h3 id="scan-알고리즘엘레베이터-스케줄링-알고리즘">SCAN 알고리즘(=엘레베이터 스케줄링 알고리즘)</h3>
<p>: 헤드가 디스크 원판의 안쪽 끝과 바깥쪽 끝을 오가며 그 경로에 존재하는 모든 요청을 처리</p>
<ul>
<li>헤드는 정해진 방향으로 이동하면서 길목에 있는 요청을 처리하며 지나감</li>
<li>SCAN 알고리즘에서는 FCFS 처럼 불필요한 헤드의 이동이 발생하거나 SSTF처럼 일부 지역에 오래 기다리는 현상이 발생하지 않는다.</li>
<li><em>→ 효율성과 형평성을 모두 만족*</em></li>
<li>한번만 이동하면 현재 큐에 들어온 모든 요청을 처리할 수 있으므로 이동거리 측면에서 매우 효율적</li>
<li>헤드가 전체 실린더를 한 번 스캔하는 시간이면 기다리던 모든 요청이 처리되므로 일부 요청이 지나치게 오래 기다리는 현상도 발생하지 않는다</li>
</ul>
<h3 id="c-scan-알고리즘">C-SCAN 알고리즘</h3>
<p>: 다른 쪽 끝에 도달해 방향을 바꾼 후에는 요청을 처리하지 않고 곧바로 출발점으로 다시 이동만 한다.</p>
<ul>
<li>SCAN 보다 헤드의 이동거리는 조금 길어지지만 탐색시간의 편차를 줄일 수 있다는 것이 장점</li>
</ul>
<h3 id="look과-c-look-알고리즘">LOOK과 C-LOOK 알고리즘</h3>
<h4 id="look">LOOK</h4>
<p>: 헤드가 한쪽 방향으로 이동하다가 그 방향에 더이상 대기 중인 요청이 없으면 헤드의 이동 방향을 즉시 반대로 바꾸는 스케줄링 방식</p>
<h4 id="c-look">C-LOOK</h4>
<p>: 전방에 요청이 없을 때 방향을 바꾼다는 측면에서 LOOK과 유사하며 한쪽 방향으로 이동할 때에만 요청을 처리한다는 것에서 C-SCAN과 유사하다.</p>
<h2 id="다중-디스크-환경에서의-스케줄링">다중 디스크 환경에서의 스케줄링</h2>
<p>: 다중 디스크를 사용하면 시스템의 성능과 신뢰성을 동시에 향상시킬 수 있다.</p>
<ul>
<li>같은 데이터가 저장되어 있는 여러개의 디스크 중 어느 디스크에서 요청을 처리할지 결정하는 스케줄링 문제가 발생</li>
<li>탐색시간을 줄이는 것이 목표라면 여러 디스크 중에서 헤드의 현재 위치가 요청한 데이터와 가장 가까운 디시크를 선택하는 방법을 사용
→디스크 간의 부하균형을 이루는 것이 중요</li>
</ul>
<blockquote>
<p>최근 전력 소모를 줄이는 것이 디스크 관리의 또 다른 중요한 목표로 인식
일부 디스크 요청을 집중시키고 나머지 디스크는 회전을 정지시키는 것이 더 효과적이다.</p>
</blockquote>
<h2 id="디스크의-저전력-관리">디스크의 저전력 관리</h2>
<h3 id="비활성화-기법">비활성화 기법</h3>
<p>디스크의 상태는 전력 소모를 기준으로 크게 네가지 상태</p>
<ul>
<li>활동 상태
: 현재 헤드가 데이터를 읽거나 쓰고 있는 상태</li>
<li>공회전 상태
: 디스크가 회전 중이지만 데이터를 읽거나 쓰지 않는 상태</li>
<li>준비 상태
: 디스크가 회전하지 않지만 인터페이스가 활성화된 상태</li>
<li>휴면 상태
: 디스크가 회전하지 않고 인터페이스도 비활성화된 상태</li>
</ul>
<blockquote>
<p>비활성 상태에서 데이터를 읽고 쓰려면 활성 상태보다 시간과 전력 소모가 더 따른다.
후속 요청까지의 시간간격이 일정 시간이상일 경우 디스크의 회전을 정지시키는 것이 전력 소모를 절감하는데 효과적</p>
</blockquote>
<h4 id="디스크의-비활성화-시점을-결정하는-방법">디스크의 비활성화 시점을 결정하는 방법</h4>
<ul>
<li>시간기반
: 일정 시간 동안 디스크가 공회전 상태이면 장치를 정지시켰다가 다시 요청왔을때 디스크를 활성화</li>
<li>예측기반
: 과거 요청을 관찰하여 다음 공회전 구간의 길이를 예측한 후 디스크를 비활성화 할 시점 결정</li>
<li>확률기반
: 디바이스의 상태 변경 시간 간격을 구하기 위해 활률 분포를 통해 요청을 모델링</li>
</ul>
<h3 id="회전속도-조절-기법">회전속도 조절 기법</h3>
<p>: 디스크의 전력 소모를 줄이기 위한 방법으로 최근에는 디스크이 회전속도를 가변적으로 조절하는 기법 제안</p>
<ul>
<li>멀티미디어 환경에서는 시간에 따른 순차적인 데이터 접근이 이뤄지므로 주기성과 규칙성이 있어 미래의 참조에 대한 예측이 비교적 정확하게 이뤄짐</li>
</ul>
<h3 id="디스크의-데이터-배치-기법">디스크의 데이터 배치 기법</h3>
<p>: 디스크이 용량은 매년 빠른 속도로 증가하나 디스크의 접근 속도는 기계적 메커니즘으로 큰 발전이 없다.</p>
<ul>
<li>디스크 내의 데이터 복제본을 많이 만들어 헤드 위치에서 가까운 복제본에 접근하도록해 빠른 응답시간과 전력 소모량 절감을 얻는 FS2 파일 시스템을 제안</li>
<li>일관성 문제 발생할 수 있으나 주소 테이블에 무효화 연산만을 수행해 쓰기 연산의 효율성을 높였다.</li>
</ul>
<h3 id="버퍼캐싱-및-사전-인출-기법">버퍼캐싱 및 사전 인출 기법</h3>
<p>: 미래에 요청될 데이터를 미리 알거나 어느 정도 예측할 수 있다면 디스크가 활성 상태일 때 헤드 위치로부터 가까운 데이터를 사전 인출해 향후 디스크의 비활성화 가능성을 높여 전력소모를 줄일 수 있다.</p>
<ul>
<li>긴급한 요청이 아닌 경우 디스크의 활성 상태 여부에 따라 요청을 최대한 지연 시키는 방식</li>
</ul>
<h3 id="쓰기전략을-통한-저전력-디스크-기법">쓰기전략을 통한 저전력 디스크 기법</h3>
<p>: 디스크가 활성상태로 돌아왔을 때 쓰는 방식으로 전력 소모를 줄이는 방안이 연구됨</p>
<ul>
<li>활성상태가 아니몀 일단 블록드을 로그 디스크에 썼다가 디스크가 활성상태로 돌아왔을 떄 디스크에 쓰기연산을 수행하는 방식</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS 기초] 운영체제와 정보기술]]></title>
            <link>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%A0%95%EB%B3%B4%EA%B8%B0%EC%88%A0-b0kgm9pb</link>
            <guid>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%A0%95%EB%B3%B4%EA%B8%B0%EC%88%A0-b0kgm9pb</guid>
            <pubDate>Tue, 27 Sep 2022 23:44:10 GMT</pubDate>
            <description><![CDATA[<h1 id="08-가상메모리">08. 가상메모리</h1>
<p>프로그램이 CPU에서 실행되려면 실행에 필요한 부분이 메모리에 올라와 있어야한다. 시분할 환경에서는 한정된 메모리 공간을 여러 프로그램이 조금씩 나누어 사용하는데 <strong>어느 정도의 메모리를 할당할 것인가</strong>에 대한 문제를 해결할 필요가 있다.
<br />
운영체제는 공평하게 같은 크기의 메모리를 할당하기 보다 집중적으로 메모리를 할당하고 다시 메모리를 회수해 다른 프로그램에 메모리를 할당하는 방식을 선택한다.
<br />
프로그램이 실행되기 위해 그 프로세스의 주소 공간 전체가 메모리에 올라갈 필요는 없다. CPU에서 당장 수행해야 할 부분만 올려두고 그렇지 않은 부분은 디스크의 스왑 영역에 내려놓는다.
이렇게 되면 자기 자신만의 메모리 주소 공간을 가정할 수 있는데 이러한 메모리 공간을 <strong>가상메모리</strong>라고 한다.</p>
<h4 id="가상메모리">가상메모리</h4>
<p>: 프로세스마다 각각 0번지부터 주소공간을 가지게 되며, 이 공간 중 일부는 물리적 메모리에 적재되고, 일부는 디스크의 스왑 영역에 존재한다.
적재 방식으로는 <strong>요구 페이징</strong>과 <strong>요구 세그먼테이션</strong>이 있다.</p>
<h2 id="요구-페이징">요구 페이징</h2>
<p>: 프로그램 실행 시 프로세스를 구성하는 모든 페이지를 한꺼번에 메모리에 올리는 것이 아니라 당장 사용될 페이지만 올리는 방식</p>
<ul>
<li>메모리 사용량이 감소</li>
<li>프로세스 전체를 메모리에 올리는데 소요되는 입출력 오버헤드도 줄인다.</li>
<li>응답시간 단축</li>
<li>시스템이 더 많은 프로세스를 수용</li>
<li>프로그램이 물리적 메모리의 용량 제약을 벗어날 수 있도록 한다.</li>
</ul>
<h4 id="유효-무효-비트">유효-무효 비트</h4>
<p>: 어떤 페이지가 메모리에 올라와 있는지 구별하기 위해 사용하고 페이지 테이블의 각 항목별로 저장된다.</p>
<blockquote>
<p>CPU가 참조하려는 페이지가 현재 메모리에 올라와 있지 않아 유효-무효 비트가 무효로 세팅되어 있는 경우를 <strong>&#39;페이지 부재&#39;</strong>가 일어났다고 한다.</p>
</blockquote>
<h3 id="요구-페이징의-페이지-부재-처리">요구 페이징의 페이지 부재 처리</h3>
<ol>
<li>CPU가 무표 페이지에 접근시 주소 변환을 담당하는 하드웨어 MMU가 페이지 부재 트랩을 발생</li>
<li>CPU의 제어권이 커널모드로 전환</li>
<li>운영체제의 페이지 부재 처리 루틴 호출되어 페이지 부재를 처리</li>
</ol>
<p>→ 페이지를 메모리에 적재하기 전 해당 페이지에 대한 접근이 적합한지 먼저 확인</p>
<blockquote>
<p>요청된 페이지를 디스크로 부터 메모리로 적재하는데 오랜 시간이 소요된다.
따라서 페이지 부재를 발생시킨 프로세스는 CPU를 뺏기고 봉쇄상태가 된다.
수행되던 CPU 레지스터 상태 및 프로그램 카운터 값을 프로세스 제어블록에 저장해 이 프로세스가 다시 CPU를 할당받을 때와 같은 상태에서 디스크로 부터 메모리를 적재한다.</p>
</blockquote>
<h4 id="적재-방법">적재 방법</h4>
<ol>
<li>디스크 입출력이 완료되어 인터럽트 발생</li>
<li>페이지 테이블에서 해당 페이지의 유효-무효 비트를 유효로 설정</li>
<li>봉쇄되었던 프로세스를 준비큐로 이동</li>
<li>CPU를 할당받으면 프로세스 제어블록에 저장해두었던 값을 복원</li>
</ol>
<h3 id="요구-페이징의-성능">요구 페이징의 성능</h3>
<p>: 성능에 가장 큰 영향을 미치는 것은 <strong>페이지 부재의 발생 빈도</strong>이다.
유효 접근시간이 짧을 수록 요구 페이징 기법의 성능은 향상된다.</p>
<h2 id="페이지-교체">페이지 교체</h2>
<p>: 페이지 부재가 발생하면 요청된 페이지를 디스크에서 메모리로 읽어와야한다. 
이때 물리적 메모리에 빈 프레임이 존재하지 않을 수 있다. 
메모리에 올라와 있는 페이지 중 하나를 디스크로 쫒아내 메모리에 빈 공간을 확보하는 작업</p>
<ul>
<li>교체 알고리즘 : 페이지 교체를 할 때 어떤 프레임에 있는 페이지를 쫒아낼 것인지 결정하는 알고리즘<ul>
<li>페이지 부재율 최소화 : 가까운 미래에 참조될 가능성이 가장 적은 페이지를 선택행 성능 향상</li>
</ul>
</li>
<li>페이지 참조열 : 참조되는 페이지들의 번호를 시간 순서에 따라 나열</li>
</ul>
<h3 id="최적-페이지-교체min-opt">최적 페이지 교체(=MIN, OPT)</h3>
<p>: 먼 미래에 참조될 페이지를 쫒아내는 방식</p>
<ul>
<li>미래에 어떤 페이지가 어떠한 순서로 참조될지 미리 알고 있다는 전제하에 알고리즘을 운영하기 때문에 온라인으로 사용하는 알고리즘은 아니다. 
→ 오프라인 알고리즘</li>
</ul>
<h3 id="선입선출-알고리즘">선입선출 알고리즘</h3>
<p>: 물리적 메모리에 가장 먼저 올라온 페이지를 우선적으로 내쫒는다.
페이지의 향후 참조 가능성을 고려하지 않고, 물리적 메모리에 들어온 순서대로 내쫒을 대상을 선정하기 때문에 비효율적</p>
<ul>
<li>물리적 메모리의 공간이 늘어나도 성능이 나빠질 수 있음
→ FIFO의 이상 현상</li>
</ul>
<h3 id="lru-알고리즘">LRU 알고리즘</h3>
<h4 id="시간지역성">시간지역성</h4>
<p>: 최근에 참조된 페이지가 가까운 미래에 다시 참조될 가능성이 높은 성질</p>
<h3 id="lfu-알고리즘">LFU 알고리즘</h3>
<p>: 페이지의 참조 횟수로 교체시킬 페이지를 결정.
과거에 참조 횟수가 가장 적었던 페이지를 쫒아내고 그 자리에 새로 참조될 페이지를 적재한다.
최저 참조 횟수를 가진 페이지들 중에서도 상대적으로 더 오래전에 참조된 페이지를 쫒아내도록 구현하는 것이 효율적이다.</p>
<h4 id="참조-횟수-계산-하는-방식">참조 횟수 계산 하는 방식</h4>
<ul>
<li>Incache-LFU
: 페이지가 물리적 메모리에 올라온 후부터의 참조 횟수를 카운트 하는 방식
페이지가 메모리에서 쫒겨났다가 다시 들어온 경우 참조 횟수를 다시 1부터 카운트</li>
<li>Perfect-LFU
: 메모리에 올라와 있는지 여부와 상관없이 페이지의 총 참조 횟수를 카운트<ul>
<li>페이지의 참조 횟수를 정확히 반영할 수 있다는 장점</li>
<li>메모리에서 쫒겨난 페이지의 참조 기록까지 모두 보관해야해 오버헤드가 상대적으로 더 큼</li>
</ul>
</li>
</ul>
<blockquote>
<p>LFU 알고리즘 &amp; LRU 알고리즘</p>
</blockquote>
<ul>
<li>LFU 알고리즘
: 오랜 시간 동안의 참조 기록을 반영할 수 있는 장점</li>
<li>LRU 알고리즘
: 시간에 따른 페이지 참조의 변화를 반영하고 LRU 보다 구현이 복잡하다는 단점이 있음</li>
</ul>
<h3 id="클럭-알고리즘nur-not-used-recently-nru-not-recently-used">클럭 알고리즘(NUR-Not Used Recently, NRU-Not Recently Used)</h3>
<p>: 하드웨어적인 지원을 통해 이와 같은 알고리즘의 운영 오버헤드를 줄인 방식.
오랫동안 참조되지 않은 페이지 중 하나를 교체.
하드웨어적인 지원으로 동작하기 때문에 LRU에 비해 페이지의 관리가 훨씬 빠르고 효율적으로 이뤄진다.</p>
<ul>
<li>교체할 페이지를 선정하기 위해 페이지 프레임들의 참조비트를 순차적으로 조사</li>
</ul>
<h4 id="참조비트">참조비트</h4>
<p>: 각 프레임마다 하나씩 존재하고 참조될 때 하드웨어에 의해 1로 자동 세팅된다.
참조비트가 1인 페이지는 0으로 바꾼 후 그냥 지나가고 참조비트가 0일 페이지는 교체</p>
<ul>
<li>참조비트 정보는 시계방향으로 따라가며 조사</li>
<li>시곗바늘이 가리키는 페이지의 참조비트가 비트가 1인 경우 클럭 알고리즘은 참조비트를 0으로 바꾼 후 시곗바늘을 한 칸 진행시키고 참조비트가 0인 페이지를 찾으면 그 페이지를 교체</li>
</ul>
<h2 id="페이지-프레임의-할당">페이지 프레임의 할당</h2>
<p>: 여러 프로세스가 수행될 때 메모리 공간을 할당하는 방법이 필요한데 이 때 할당 알고리즘이 사용된다.</p>
<h4 id="할당-알고리즘">할당 알고리즘</h4>
<ul>
<li>균등할당
: 모든 프로세스에게 페이지 프레임을 균일하게 할당</li>
<li>비례할당
: 프로세스의 크기에 비례해 페이지 프레임 할당</li>
<li>우선순위 할당
: 프로세스의 우선순위에 따라 페이지 프레임을 다르게 할당</li>
</ul>
<blockquote>
<p>프로세스를 정상적으로 수행하기 위해 적어도 일정 수준 이상의 페이지 프레임을 각 프로세스에 할당해야 한다.
반복문을 실행중이라면 반복문을 구성하는 페이지들을 한꺼번에 메모리에 올리는 것이 유리하다.
프로세스에게 최소한으로 필요한 메모리의 양은 시간에 따라 다를 수 있다.</p>
</blockquote>
<h2 id="전역교체와-지역교체">전역교체와 지역교체</h2>
<ul>
<li>전역교체
: 모든 페이지 프레임이 교체 대상이 될 수 있는 방법<ul>
<li>교체 알고리즘에 근거해 할당되는 메모리 양이 가변적으로 변하는 방법</li>
<li>페이지 교체 시 다른 프로세스에 할당된 프레임을 빼앗아 올 수 있는 방식</li>
</ul>
</li>
<li>지역교체
: 현재 수행중인 프로세스에게 할당된 프레임 내에서만 교체 대상을 선정할 수 있는 방법<ul>
<li>페이지 프레임을 미리 할당하는 것을 전제</li>
<li>프로세스별로 페이지 프레임을 할당하고 교체할 페이지도 그 프로세스에게 할당되 ㄴ프레임 내에서 선정하게 되는 것
→ LRU,LFU를 독자적으로 운영할 때 지역교체 방법 사용</li>
</ul>
</li>
</ul>
<h2 id="스레싱">스레싱</h2>
<p>: 집중적으로 참조되는 페이지들의 집합을 메모리에 한꺼번에 적재하지 못하면 페이지 부재율이 크게 상승해 CPU 이용률이 떨어질 수 있는데 이것을 <strong>스레싱</strong>이라고 한다.</p>
<h4 id="스레싱-발생-시나리오">스레싱 발생 시나리오</h4>
<ol>
<li>CPU 이용률이 낮을 경우 운영체제는 MPD를 높이게 된다.</li>
<li>MPD가 과도하게 높아지면 각 프로세스에게 할당되는 메모리의 양이 지나치게 감소된다.</li>
<li>각 프로세스는 그들이 원할하게 수행되기 위해 필요한 최소한의 페이지 프레임도 할당받지 못하는 상태가 된다.</li>
<li>페이지 부재가 발생하면 디스크 I/O 작업을 수반해 문맥교환을 통해 다른 프로세스에게 CPU가 이양된다.</li>
<li>이때 다른 프로세스 역시 메모리 양이 적으면 페이지 부재가 발생한다.</li>
<li>이것이 반복되어 준비 큐에 있는 모든 프로세스에 CPU가 할당되어도 페이지 부재를 발생시키면  스왑 인/아웃을 지속적으로 발생시켜 CPU는 대부분 시간에 일을 하지 않게 된다.</li>
</ol>
<ul>
<li>MPD와 CPU 이용률의 상관관계
<img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/3801907c-1a03-46a7-93b6-c04e824fbc97/image.jpg" alt=""></li>
</ul>
<p>: 메모리 내에 존재하는 프로세스의 수를 증가시키면 CPU 이용률은 이에 비례해 증가된다. 한계치를 넘어서면 CPU 이용률이 급격히 떨어져 스레싱이 발생해 CPU이용률을 최대한 높일 수 있도록 MPD를 조절해야 한다.
CPU 이용률을 높이고 스레싱을 방지하는 방법에는 <strong>워킹셋 알고리즘</strong>과 <strong>페이지 부재 빈도 알고리즘</strong>이 있다.</p>
<h3 id="워킹셋-알고리즘">워킹셋 알고리즘</h3>
<p>: 지역성 집합이 메모리에 동시에 올라갈 수 있도록 보장하는 메모리 관리 알고리즘.
프로세스가 일정 시간 동안 원활히 수행되기 위해 한꺼번에 메로리에 올라와 있어야하는 페이지들의 집합을 워킹셋이라고 정의.
프로세스의 워킹셋을 구성하는 페이지들이 한꺼번에 메모리에 올라갈 수 있는 경우에만 그 프로세스에게 메모리를 할당</p>
<h4 id="지역성-집합">지역성 집합</h4>
<p>: 집중적으로 참조되는 페이지들의 집합</p>
<ul>
<li>메모리에 올라와 있는 프로세스들의 워킹셋 크기의 합이 프레임 수보다 클 경우 일부 프로세스를 스왑아웃 시켜 남은 프로세스의 워킹셋이 메모리에 모두 올라가는 것을 보장</li>
</ul>
<h3 id="페이지-부재-빈도-알고리즘">페이지 부재 빈도 알고리즘</h3>
<p>: 프로세스의 페이지 부재율을 주기적으로 조사하고 이 값에 근그해 각 프로세스에 할당할 메모리 양을 동적으로 조절</p>
<ul>
<li>미리 정해놓은 상한값을 넘게 되면 이 프로세스의 할당된 프레임 수가 부족하다고 판단해 이 프로세스에게 프레임을 추가로 할당</li>
<li>페이지 부재율이 하한값 이하로 떨어지면 이 프로세스에게 필요 이상으로 많은 프레임이 할당된 것으로 간주해 할당된 프레임 수를 줄인다.
→ 이러한 원리로 MPD를 조절하면서 CPU이용률을 높이는 동시에 스레싱을 방지한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next 초기 설정]]></title>
            <link>https://velog.io/@sohyeonbak_oly/Next-%EC%B4%88%EA%B8%B0-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@sohyeonbak_oly/Next-%EC%B4%88%EA%B8%B0-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Mon, 26 Sep 2022 14:02:14 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>Next.js: The React Framework</strong>
Next.js는 리엑트 어플리케이션에서 SSR을 쉽게 구현해주는 프레임워크이다.</p>
</blockquote>
<h2 id="기능">기능</h2>
<ul>
<li>직관적인 페이지 기반의 라우팅 시스템(<strong>다이나믹 라우팅</strong>도 지원)</li>
<li><code>Pre-rendering</code>, <code>SSG(static generation)</code>과 <code>SSR(server-side rendering)</code> 둘 다 페이지 기반 단위에서 지원해준다.</li>
<li>자동 <code>code spliting</code>으로 빠른 페이지 로드</li>
<li>최적화된 <code>prefetching</code>과 함께 <code>Client-side routing</code></li>
<li><code>Built-in CSS</code>와 Sass 지원, CSS-in-JS 라이브러리 지원</li>
<li><code>Fast Refresh</code>과 함께 개발 환경 지원</li>
<li>serverless 함수로 API 엔드포인트를 빌드하기 위한 API routes</li>
<li>충분한 확장성<code>(webpack, babel 등)</code></li>
</ul>
<blockquote>
<p><strong>📌 Pre-rendering</strong>
기본적으로 Next.js는 모든 페이지를 미리 렌더한다.
이것은 Next.js가 클라이언트 측 JavaScript로 모든 것을 수행하는 대신 각 페이지에 대해 미리 HTML을 생성하는 것을 의미한다.
Pre-rendering은 SEO와 performance에서 더 나은 결과를 가져올 수 있다.
각각 생성된 HTML은 각 페이지에 필요한 최소한의 JavaScript 코드와 연관되어진다.
페이지를 브라우저에서 로드할 때, JavaScript 코드는 페이지에 충분한 인터렉션이 만들어지고 수행된다. (이 과정은 hydration 이라고 한다.)</p>
</blockquote>
<h2 id="초기-세팅">초기 세팅</h2>
<ul>
<li><p>라이브러리 추가
<code>yarn add next react react-dom</code></p>
</li>
<li><p>package.json &#39;scripts&#39;에 추가</p>
<pre><code class="language-javascript">&quot;scripts&quot;: {
&quot;dev&quot;: &quot;next dev&quot;, // deveopment 모드에서 실행
&quot;build&quot;: &quot;next build&quot;, // 상품 사용을 위한 어플리케이션 빌드 실행
&quot;start&quot;: &quot;next start&quot;, // production 서버에서 실행
&quot;lint&quot;: &quot;next lint&quot; // built-in ESLint configuration
}</code></pre>
</li>
<li><p>&#39;pages&#39;, &#39;public&#39; 폴더 생성</p>
</li>
</ul>
<h4 id="_appjs">_app.js</h4>
<p>: Next.js 에서 app 컴포넌트는 초기 페이지로 사용한다. app 컴포넌트를 사용해 페이지 초기를 조정할 수 있다.</p>
<ul>
<li>페이지 변경에도 지속적으로 유지할 레이아웃</li>
<li>페이지 탐색할 때 상태 유지</li>
<li>커스텀 에러를 <strong>&#39;componentDidCatch&#39;</strong>를 사용해 다룰 수 있음</li>
<li>페이지에 추가된 데이터를 삽입</li>
<li>global CSS를 사용</li>
</ul>
<h4 id="_documentjs">_document.js</h4>
<p>: document는 <code>&lt;html&gt;</code>, <code>&lt;body&gt;</code> 태그를 페이지 렌더에 사용하기 위해 업데이트 할 수 있다. 이 파일은 오직 서버에서 렌더되고 onClick같은 이벤트 핸들러는 사용할 수 없다. _app 다음에 실행된다.</p>
<h4 id="indexjs">index.js</h4>
<p>: 경로는 자동적으로 파일 이름으로 지정되는데 디렉토리의 root파일은 index.js가 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS 기초] 운영체제와 정보기술]]></title>
            <link>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%A0%95%EB%B3%B4%EA%B8%B0%EC%88%A0-mqn0i2vk</link>
            <guid>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%A0%95%EB%B3%B4%EA%B8%B0%EC%88%A0-mqn0i2vk</guid>
            <pubDate>Tue, 20 Sep 2022 23:42:34 GMT</pubDate>
            <description><![CDATA[<h1 id="07-메모리-관리">07. 메모리 관리</h1>
<p>메모리 주소: 이진수(32비트/64비트 주소체계)
byte 단위로 메모리 주소 부여해준다.</p>
<h2 id="주소-바인딩">주소 바인딩</h2>
<h4 id="논리적주소">논리적주소</h4>
<p>: 프로그램이 실행을 위해 메모리에 적재되면 그 프로세스를 위한 독자적인 공간이 생긴다.
CPU는 프로세스마다 이 논리적 주소에 근거해 명령을 실행한다.</p>
<h4 id="물리적주소">물리적주소</h4>
<p>: 실제로 올라가 있는 위치</p>
<ul>
<li>프로세스는 물리적 메모리에 올라가 있어야 함</li>
<li>CPU가 명령어를 실행하기 위해 논리적 주소 참조</li>
<li>논리적 주소는 물리적 메모리의 어느 위치에 맵핑되어 있는지 확인 필요
→ <strong>주소 바인딩</strong></li>
</ul>
<h3 id="주소-바인딩-1">주소 바인딩</h3>
<h4 id="컴파일-타임-바인딩">컴파일 타임 바인딩</h4>
<p>: 물리적 메모리 주소가 프로그램을 컴파일 할 때 결정되는 주소 바인딩 방식</p>
<ul>
<li>컴파일 시점에 물리적 메모리 주소 결정</li>
<li>절대 주소로 적재된다는 뜻으로 <strong>적재코드</strong>를 생성하는 바인딩 방식</li>
</ul>
<h4 id="로드타임-바인딩">로드타임 바인딩</h4>
<p>: 프로그램의 실행이 시작 될 때 물리적 메모리 주소가 결정</p>
<ul>
<li>사용자 프로그램을 메모리에 적재시키는 프로그램<ul>
<li>로더의 책임하에 물리적 메모리가 부여되고, 프로그램이 종료될 때까지 위치를 고정한다.</li>
<li>컴파일러 재배치 가능 코드를 생성한 경우 가능한 주소 바인딩 방식</li>
</ul>
</li>
</ul>
<h4 id="실행시간-바인딩">실행시간 바인딩</h4>
<p>: 프로그램이 실행을 시작한 후 위치한 물리적 메모리 주소가 변경되는 방식</p>
<ul>
<li>주소맵핑 테이블로 바인딩 점검</li>
<li>필요요건<ul>
<li>기준레지스터</li>
<li>한계레지스터</li>
<li>MMU(Memory Management Unit: 메모리 관리 유닛)</li>
</ul>
</li>
</ul>
<blockquote>
<p>MMU 기법
: 주소값에 기준레지스터 값을 더해 물리적 주소를 얻어냄
(여기서 기준 레지스터는 재배치 레지스터로 물리적 주소를 가짐)</p>
</blockquote>
<ul>
<li><strong>다중 프로그래밍 환경</strong>
: 물리적 메모리 안에 여러 프로세스가 올라올 경우 MMU 방식으로 주소변환을 하면 CPU가 요청한 논리적 주소와 재배치 레지스터 값을 더한 결과가 주소공간을 벗어날 수 있다.
→ 이런 문제를 해결하기 위해 <strong>한계 레지스터</strong>를 사용</li>
<li><strong>한계 레지스터</strong>
: 프로세스가 자신의 공간을 넘어 참조하는지 체크
현재 CPU에서 수행중인 프로세스의 논리적 주소의 최대 값을 담고 있다.
<img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/6b90de47-9913-47e1-8c30-57f0f379cce3/image.JPG" alt=""></li>
</ul>
<h2 id="메모리-관리와-관련-용어">메모리 관리와 관련 용어</h2>
<h3 id="동적로딩">동적로딩</h3>
<p>: 다중 프로그래밍 환경에서 메모리 사용의 효율을 높이기 위해 사용하는 기법</p>
<ul>
<li>해당 부분 안 메모리에 적재</li>
<li>동적 로딩 기법은 사용되지 않는 많은 코드가 올라가는 것을 막아 효율적으로 사용할 수 있다.</li>
</ul>
<h3 id="동적-연결">동적 연결</h3>
<blockquote>
<p><strong>연결</strong>
프로그래머가 작성한 코드를 컴하일한 목적 파일, 이미 컴파일 라이브러리 파일을 묶어 하나의 실행 파일을 생성하는 과정</p>
</blockquote>
<p>: 목적 파일과 라이브러리 파일 사이 연결 프로그램 실행 시점까지 지연시키는 기법</p>
<ul>
<li>라이브러리 실행 시점에 연결</li>
<li>실행 파일에 라이브러리 코드 포함하지 않음</li>
<li>프로그램 실행 후 라이브러리 함수 호출할 때 연결이 이뤄짐<ul>
<li>스텁 : 라이브러리 호출 시 위치를 찾기 위한 코드
→ 스텁을 통해 라이브러리가 메모리에 있는지 확인</li>
</ul>
</li>
</ul>
<h3 id="중첩≒-동적로딩-그러나-사용-이유가-다름">중첩(≒ 동적로딩, 그러나 사용 이유가 다름)</h3>
<p>: 프로세스의 주소공간을 분할해 실제 필요한 부분만 메모리에 적재</p>
<ul>
<li>프로그램 크기가 메모리보다 작다면 한꺼번에 올리지만 크다면 분할해 올림</li>
<li>단일 프로세스만 메모리에 올려 놓는 환경에서 메모리보다 큰 프로세스를 실행하기 위한 방법</li>
</ul>
<h3 id="스와핑">스와핑</h3>
<p>: 메모리에 올라온 프로세스의 주소 공간 전체를 디스크 스왑영역에 일시적으로 내려 놓는것</p>
<blockquote>
<p><strong>백킹스토어</strong>
디스크 내에 파일 시스템과 별도로 존재하는 영역</p>
</blockquote>
<ul>
<li>프로세스가 수행 중인 동안에만 디스크에 일시적으로 저장하는 공간으로 저장 기간이 상대적으로 짧다.</li>
<li>특정한 이유로 수행 중인 프로세스의 주소 공간을 일시적으로 메모리에서 디스크로 내려 놓는것</li>
<li>스와핑 방향에 따라 <strong>스왑인 (디스크→메모리)</strong>, <strong>스왑아웃(메모리→디스크)</strong></li>
</ul>
<h4 id="스와핑-과정">스와핑 과정</h4>
<ul>
<li>스와퍼(동기 스케줄러)로 스왑 아웃 시킬 프로세스 선정</li>
<li>선정된 프로세스는 메모리에 올라간 주소 공간을 통때로 리스크 스왑 영역에 스왑 아웃
→ 메모리에 존재하는 프로세스 수 조절이 중요</li>
<li>메모리에 프로그램이 충분히 실행되면 사용중이던 프로그램을 메모미에서 내쫒고 스왑 아웃된 프로그램을 다시 올림<ul>
<li>컴파일, 로드 타임 바인딩은 스왑아웃 후 인 될 때 나왔던 자리로 들어가나 실시간 바인딩은 빈 메모리 영역 아무곳으로 들어간다.</li>
</ul>
</li>
</ul>
<h2 id="물리적-메모리의-할당-방식">물리적 메모리의 할당 방식</h2>
<ul>
<li>운영체제 상주 영역
: 인터럽트 백터 와 함께 메모리의 낮은 주소 영역에 사용되고 커널에 위치한다.</li>
<li>사용자 프로세스 영역
: 물리적 메모리 높은 주소 영역에 사용되고 사용자 프로세스가 이곳에 적재된다.</li>
</ul>
<h3 id="사용자-프로세스-영역의-관리-방법">사용자 프로세스 영역의 관리 방법</h3>
<h4 id="연속-할당">연속 할당</h4>
<p>: 물리적 메모리의 연속적 공간에 올리는 방식
→ 하나의 분할, 하나의 프로세스에 적재</p>
<ul>
<li><p>고정 분할
: 물리적 메모리 주소를 주어진 개수 만큼 영구적으로 분할해 하나의 프로세스를 적재해 실행
⎼ 동시에 올릴 수 있는 수 고정
⎼ 최대 크기 제한</p>
<ul>
<li><p>외부조각 : 프로그램의 크기보다 분할 크기가 작은 경우 분할이 비었음에도 적재가 안되는 경우 
⎼ 특정 프로그램에 배당된 공간 X</p>
</li>
<li><p>내부조각 : 프로그램 크기보다 분할 크기가 큰 경우 프로그램을 적재 후 남는 메모리 공간에 실행</p>
</li>
</ul>
</li>
<li><p>가변분할 
: 분할 크기, 개수가 동적으로 변하는 것</p>
<blockquote>
<p>  <strong>컴팩션</strong>(외부조각 문제 해결방법)
: 물리적 메모리 중 사용 중인 메모리 영역을 한 쪽으로 몰고 가용공간을 다른 쪽으로 모아 큰 가용 공간을 만드는 방법
→ 비용이 큼</p>
</blockquote>
<ul>
<li>동적 메모리 할당 문제
: 프로세스를 메모리에 올릴 때 가용공간 중 어떤 공간에 올릴지 결정할 문제<ul>
<li>최초적합 방법
: 크기가 n이상인 가용공간 중 <strong>가장 먼저</strong> 찾은 곳에 할당하는 방법</li>
<li>최적적합 방법
: 크기가 n이상인 <strong>가장 작은</strong> 가용공간을 찾아 새로운 프로세스를 할당</li>
<li>최악적합 방법
: <strong>가장 크기가 큰 곳</strong>에 새로운 프로그램 할당</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="불연속할당-기법">불연속할당 기법</h4>
<p>: 하나의 프로세스가 물리적 메모리의 여러 위치에 분산되어 올라갈 수 있는 메모리 할당 기법</p>
<ul>
<li>페이징 기법</li>
<li>세그먼테이션 기법</li>
<li>페이지드 세그먼테이션 기법</li>
</ul>
<h2 id="페이징-기법">페이징 기법</h2>
<p>: 프로세스의 주소 공간을 동일한 크기의 페이지 단위로 나누어 물리적 메모리의 서로 다른 위치에 페이지들을 저장하는 방식</p>
<ul>
<li>물리적 메모리를 페이지와 동일한 크기의 프레임으로 미리 나누어 둔다.
→ 메모리에 올리는 단위가 동일한 크기의 페이지 단위이므로 미리 분할을 하더라도 빈 프레임이 있으면 어떤 위치든 사용할 수 있어서 동적 메모리 할당 문제가 발생하지 않는다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/1d947e8e-7e07-489e-a615-789afb17bc78/image.JPG" alt=""></p>
<h3 id="주소-변환-기법">주소 변환 기법</h3>
<p>: CPU가 사용하는 논리적 주소를 <strong>페이지 번호</strong>와 <strong>페이지 오프셋</strong>으로 나누어 주소 변환에 사용한다.
페이지 번호는 페이지 테이블 접근 시 인덱스로 사용되고, 인덱스 항목에는 그 페이지 의 물리적 메모리상의 기준 주소 <strong>시작 위치</strong>가 저장된다.</p>
<h3 id="페이지-테이블의-구현">페이지 테이블의 구현</h3>
<ul>
<li>자료구조</li>
<li>물리적 메모리에 위치</li>
<li>실행 중인 프로세스의 페이지 테이블에 접근 하기 위해 레지스터를 사용<ul>
<li>페이지 테이블 기준 레지스터
: 페이지 테이블의 시작 위치를 가르킴</li>
<li>페이지 테이블 길이 레지스터
: 페이지 테이블의 크기 보관</li>
</ul>
</li>
<li>메모리 접근 연산 - 2번 필요<ul>
<li>주소 변환을 위해 접근</li>
<li>변환된 주소에서 실제 데이터에 접근
→ 메모리에 접근하기 위해 두번의 접근은 오버헤드를 발생시켜 이 오버헤드를 줄이고 메모리 접근 속도를 향상시키기 위해 <strong>TLB(Translation Look-aside Buffer)</strong></li>
</ul>
</li>
</ul>
<blockquote>
<p>  <strong>TLB(Translation Look-aside Buffer)</strong>
: 고속의 주소 변환용 하드웨어 캐시 사용</p>
</blockquote>
<ul>
<li>가격이 비싸기 때문에 빈번히 참조되는 페이지에 대한 주소 변환 정보만 담는다.</li>
<li>요청된 페이지 번호가 TLB 내에 없다면 프레임 번호를 알아야한다.</li>
<li>프로세스 별로 주소 변환 정보는 다르기 때문에 문맥교환 시 TLB 내용을 모두 지워야 한다.</li>
<li>페이지 테이블과 TLB에 저장된 정보 구조 차이<ul>
<li>페이지 테이블 : 주소 변환 정보가 페이지 번호에 따라 순차적으로 들어가 있다.</li>
<li>TLB : 모든 페이지에 대한 정보가 없기 때문에 페이지 번호와 이에 대응하는 프레임 번호가 쌍으로 저장<ul>
<li>주소 변환 정보를 찾기 위해 TLB를 모두 확인해야하는 오버헤드를 줄이기 위해 병렬탐색이 가능한 <strong>연관 레지스터</strong> 사용</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="계층적-페이징">계층적 페이징</h3>
<p>: 현대 컴퓨터는 주소공간이 큰 프로그램을 지원한다.
수행 중인 프로세스 수가 증가해 전체 메모리의 상당 부분이 주소 변환을 위한 페이지 테이블에 할애되어 실제 사용가능한 메모리 공간이 줄어든다.
이러한 메모리 공간 낭비를 줄이기 위해 <strong>2단계 페이징 기법</strong>을 사용</p>
<h4 id="2단계-페이징-기법">2단계 페이징 기법</h4>
<ul>
<li>외부 페이지 테이블 : 사용되지 않는 주소 공간에 대해서 외부 페이지 테이블 항목을 Null로 설정</li>
<li>내부 페이지 테이블
→ 페이지 테이블을 위해 사용되는 메모리 공간을 줄여 공간적인 이득이 있으나 주소 변환을 위한 페이지 테이블 수가 증가하게 됨</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/ca4bab56-7e85-44b8-95be-3f08f3d8dc51/image.JPG" alt=""></p>
<blockquote>
<p>프로세스의 주소 공간이 커질 수록 페이지 테이블의 크기도 커져 다단계 페이지 테이블이 필요하다. 다단계 페이지 테이블로 메모리 공간의 소모는 줄일 수 있으나 메모리 접근시간이 늘어나는 문제가 발생한다. 이때 <strong>TLB를 함께 사용해 시간적인 효율성</strong>을 얻을 수 있다.</p>
</blockquote>
<h3 id="역페이지-테이블">역페이지 테이블</h3>
<p>: 물리적 메모리의 페이지 프레임 하나당 페이지 테이블에 하나씩의 항목을 두는 방식.
→ 논리적 주소에 대한 페이지 테이블을 만드는 것이 아닌 <strong>물리적 주소에 대한 페이지 테이블을 만드는 것</strong></p>
<ul>
<li>물리적 주소로부터 논리적 주소를 얻기 수월한 구조
→ 주소변환은 비효율적으로 진행<ol>
<li>주소 변환 요청</li>
<li>주소를 담은 페이지가 물리적 메모리에 존재하는지 여부 판단을 위해 모두 탐색</li>
</ol>
</li>
<li>연관 레지스터에 보관해 테이블 전체 항목에 대해 병렬탐색으로 시간적 효율성</li>
</ul>
<h3 id="공유-페이지">공유 페이지</h3>
<h4 id="공유코드-재진입-가능-코드-순수-코드">공유코드 (재진입 가능 코드, 순수 코드)</h4>
<p>: 메모리 공간의 효율적인 사용을 위해 여러 프로세스에 의해 공통으로 사용되도록 작성한 코드</p>
<h4 id="공유-페이지-1">공유 페이지</h4>
<p>: 공유 코드를 담고 있는 페이지</p>
<ul>
<li>물리적 메모리에 하나만 적재되 메모리를 더 효율적으로 사용</li>
</ul>
<h4 id="사유-페이지">사유 페이지</h4>
<p>: 프로세스들이 공유하지 않고 프로세스별로 독자적으로 사용하는 페이지</p>
<ul>
<li>논리적 주소 공간 중 어떠한 위치에 있어도 무방</li>
</ul>
<h3 id="메모리-보호">메모리 보호</h3>
<ul>
<li><p>보호 비트
: 각 페이지에 대한 접근 권한 내용을 담고 있음</p>
<ul>
<li>&#39;누구&#39;에 해당하는 접근 권한 설정 필요 없음</li>
<li>&#39;어떠한&#39; 접근을 허용하는지의 정보가 저장</li>
</ul>
</li>
<li><p>유효-무효 비트
: 해당 페이지의 내용이 유효한지에 대한 내용을 담고 있음</p>
<ul>
<li>유효 : 해당 메모리 프레임에 그 페이지가 존재함 - 접근 허용</li>
<li>무효 : 프로세스가 그 주소 부분을 사용하지 않거나 해당 페이지가 물리적 메모리에 올라와 있지 않고 백킹스토어에 존재 - 접근 권한 없음</li>
</ul>
</li>
</ul>
<h2 id="세그먼테이션">세그먼테이션</h2>
<blockquote>
<p>하나의 프로세스를 구성하는 주소 공간은 <strong>코드, 데이터, 스택</strong> 등 의미있는 단위로 구성</p>
</blockquote>
<h4 id="세그먼트">세그먼트</h4>
<p>: 주소 공간을 기능 단위 또는 의미 단위로 나눈 것 </p>
<ul>
<li>코드, 데이터, 스택 등 기능 단위로 세그먼트 정의</li>
<li>의미를 가질 수 있는 논리적인 단위로 나눠 크기가 균일하지 않다.</li>
<li>의미 단위의 세그먼트로 나누어 관리해 크기가 균일하지 않은 세그먼트들을 메모리에 적재하는 부가적인 관리 오버헤드가 필요</li>
<li>세그먼트 번호
: 논리적 주소가 프로세스 주소 공간에서 몇번째 속하는지 나타냄</li>
<li>오프셋
: 세그먼트 내에서 얼마만큼 떨어져 있는지에 대한 정보</li>
<li>세그먼트 테이블<ul>
<li>기준점 : 물리적 메모리에서 시작 위치</li>
<li>한계점 : 세그먼트 길이</li>
</ul>
</li>
<li>주소 변환<ul>
<li>세그먼트 테이블 기준 레지스터</li>
<li>세그먼트 테이블 길이 레지스터</li>
</ul>
</li>
</ul>
<h4 id="세그먼테이션-기법">세그먼테이션 기법</h4>
<p>논리적 주소를 물리적 주소로 변환하기 전 확인 사항</p>
<ol>
<li>요청된 세그먼트 번호가 STLR에 저장된 값보다 작은 값인지</li>
<li>논리적 주소의 오프셋값이 그 세그먼트 길이보다 작은 값인지</li>
</ol>
<h4 id="공유-세그먼트">공유 세그먼트</h4>
<p>: 공유하는 모든 프로세스의 주소공간에서 동일한 논리적 주소에 위치</p>
<ul>
<li>공유와 보안 측면에서 페이징 기법에 훨씬 효과적</li>
<li>가용공간 할당 방식에는 최초적합과 최적적합 방식이 있다.</li>
</ul>
<h2 id="페이지드-세그먼테이션">페이지드 세그먼테이션</h2>
<p>: 반드시 동일한 크기 페이지들의 집합으로 구성, 물리적 메모리에 적재하는 단위는 페이지 단위</p>
<ul>
<li>논리적 주소를 물리적 주소 변환 과정<ol>
<li>논리적 주소의 상위 비트인 세그먼트 번호를 통해 세그먼트 테이블의 해당 항목에 접근<ul>
<li>세그먼트 길이와 페이지 테이블 시작 주소가 있다.</li>
</ul>
<ol start="2">
<li>세그먼트 길이 값과 하위 비트인 오프셋 값을 비교</li>
<li>세그먼트 테이블의 항목을 통해 세그먼트를 위한 페이지 테이블로 얻은 시작 위치로 페이지 번호만큼 떨어진 페이지 테이블 항목을 찾아 페이지 프레임 위치를 얻는다.</li>
<li>떨어진 위치에 있는 곳이 물리적 메모리 주소가 된다</li>
</ol>
</li>
</ol>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[🥏 공식문서로 배우는 React]]></title>
            <link>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-b78mpe3m</link>
            <guid>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-b78mpe3m</guid>
            <pubDate>Fri, 26 Aug 2022 15:07:38 GMT</pubDate>
            <description><![CDATA[<h1 id="06-hook">06. hook</h1>
<p>hook은 클래스 컴포넌트가 아닌 곳에서 state와 리액트 기능을 사용할 수 있게 도와준다.
state와 생명주기 메서드를 함수형 컴포넌트에서 지속해서 사용 가능하도록 만들어주고 리액트에서 제공해주고 있다.</p>
<h2 id="usestate">useState</h2>
<p>컴포넌트 내에서 동적인 데이터(state)를 관리해주는 hook이다.</p>
<pre><code class="language-javascript">import React, { useState } from &#39;react&#39;;
function Example() {
  // &quot;count&quot;라는 새 상태 변수를 선언합니다
  const [count, setCount] = useState(0);
  return (
    &lt;div&gt;
      &lt;p&gt;You clicked {count} times&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;
        Click me
      &lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p><code>useState</code>는 배열 비구조분해 할당을 통해 현재 state값과 state값을 변경할 수 있는 함수로 구성되어 있다.
useState 파라미터에 넣는 값은 <strong>state의 초기 값에 해당</strong>되고, 값을 바뀌기 위해 <strong>setter함수를 사용</strong>한다.
클래스 컴포넌트에서 사용하던 state와 달리 초기 값은 객체가 아닌 primitive type 값을 넣어줄 수 있고 컴포넌트 내에 여러개를 사용 할 수도 있다.</p>
<h2 id="useeffect">useEffect</h2>
<p><code>useEffect</code>는 react class 문법에서 <code>componentDidMount</code>, <code>componentDidUpdate</code>, <code>componentWillUnmount</code>가 합쳐진 기능이다. 
공식 문서에서는 컴포넌트가 랜더링 된 이후에 어떤 일을 수행 할 수 있도록 도와주는 hook이라고 한다.
react는 effect가 수행되는 시점에 이미 DOM이 업데이트되었음을 보장해준다.</p>
<pre><code class="language-javascript">function Example() {
  const [count, setCount] = useState(0);

  // componentDidMount, componentDidUpdate와 비슷합니다
  useEffect(() =&gt; {
    // 브라우저 API를 이용해 문서의 타이틀을 업데이트합니다
    document.title = `You clicked ${count} times`;
  });
  return (
    &lt;div&gt;
      &lt;p&gt;You clicked {count} times&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;
        Click me
      &lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h3 id="useeffect-사용법">useEffect 사용법</h3>
<ul>
<li>첫번째 파라미터에는 함수가 실행된다.</li>
<li>두번째 파라미터는 dependency 배열이 옵셔널로 주어지는데 deps 배열 안 데이터가 update가 되면 <code>useEffect</code>의 함수가 실행된다.<pre><code>    : 옵셔널이기 때문에 deps 배열을 넣지 않으면 컴포넌트가 리랜더링 될 때 마다 호출되고,
    빈 배열일 경우 컴포넌트가 mount 됐을 때만 실행된다.</code></pre></li>
<li>마지막으로 <code>cleanup 함수</code>는 <code>useEffect</code>에서 함수를 반환하는 형식으로 사용된다.<ul>
<li><code>cleanup 함수</code>는 deps가 빈 배열일 경우 unmount될 때 실행된다.</li>
<li><code>deps 배열</code>에 특정 값을 넣게 된다면 컴포넌트가 처음 mount 될 때도 실행되고, deps의 데이터가 바뀌기 직전에도 호출이 되고 unmount될 때도 호출된다.</li>
</ul>
</li>
<li>useEffect 안에서 사용되는 state나 props가 있다면 deps 안에 넣어주는 것이 규칙이다<ul>
<li>그렇게 하지 않으면 state나 props를 지정해주지 않게 된다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>📌 react는 부모 컴포넌트가 리랜더링되면 자식 컴포넌트도 같이 리랜더링을 실행하지만 실제 데이터가 바뀐 부분만 DOM에 적용된다.
하지만 virtual DOM에는 모든 리랜더링에 대응하고 있게 된다.</p>
<p>📌 react의 함수 컴포넌트는 데이터가 변경되면 함수 컴포넌트를 전체 다시 실행시킨다. 
react hook을 사용하게 되면 hook에 사용된 데이터를 react에서 메모리에 저장해둬서 다시 함수를 실행시켜도 초기 데이터가 아닌 변경된 데이터를 유지시켜주게 되는 것이다.</p>
</blockquote>
<h2 id="useref">useRef</h2>
<p>먼저 <code>ref</code>는 render에서 생성된 DOM 노드나 리액트 엘리먼트에 접근할 때 사용한다.</p>
<blockquote>
<p>공식문서 ref를 사용해야 할 때는 다음과 같다.</p>
</blockquote>
<ul>
<li>포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때.</li>
<li>애니메이션을 직접적으로 실행시킬 때.</li>
<li>서드 파티 DOM 라이브러리를 React와 같이 사용할 때.</li>
</ul>
<p><code>useRef</code>는 <code>.current</code> 프로퍼티로 전달된 인자로 초기화 된 객체를 가진다. 
즉 .current 프로퍼티에 변경 가능한 값을 담고 있는 상자를 만드는 것이다.
useRef는 순수 자바스크립트 객체를 생성하고, 그렇기 때문에 <code>useRef</code> 내용이 변경되면 그것을 알려주지 않는다.
리액트에서 DOM 노드를 변경하고 싶을 때 콜백 ref를 사용할 수 있다.</p>
<pre><code class="language-javascript">function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () =&gt; {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    &lt;&gt;
      &lt;input ref={inputEl} type=&quot;text&quot; /&gt;
      &lt;button onClick={onButtonClick}&gt;Focus the input&lt;/button&gt;
    &lt;/&gt;
  );
}</code></pre>
<h2 id="usememo">useMemo</h2>
<p><code>useMemo</code>는 성능 최적화에 사용되는 hook이다.
메모이제이션을 해준다는 뜻으로 useMemo로 사용되는데, 특정 결과 값을 재사용 해준다.</p>
<pre><code class="language-javascript">const memoizedValue = useMemo(() =&gt; computeExpensiveValue(a, b), [a, b]);</code></pre>
<h3 id="usememo의-사용법">useMemo의 사용법</h3>
<ul>
<li>생성함수와 의존성 데이터를 배열에 전달해준다.<ul>
<li>배열에 담긴 의존성 데이터가 변경될 때만 랜더링을 해주고, 배열이 없는 경우 매 랜더링에 새 값을 계산해준다.</li>
</ul>
</li>
</ul>
<h2 id="usecallback">useCallback</h2>
<p>함수 컴포넌트가 계속 호출되어도 동일한 데이터를 가지고 해당 컴포넌트의 지역함수를 호출하고 싶을때 사용한다.
<code>useCallback</code>는 해당 컴포넌트의 state나 props가 변경되어도 캐시에 저장된 캡쳐된 데이터를 가지고 함수를 실행시킨다.</p>
<pre><code class="language-javascript">const memoizedCallback = useCallback(
  () =&gt; {
    doSomething(a, b);
  },
  [a, b],
);</code></pre>
<h3 id="usecallbak의-사용법">useCallbak의 사용법</h3>
<ul>
<li>두번째 파라미터 deps 배열에 변경해줘야하는 state나 props를 넣어줘야한다.</li>
<li>또한 함수안에서 사용하는 state나 props가 있다면 deps 배열에 넣어줘야한다.</li>
</ul>
<h2 id="usereducer">useReducer</h2>
<p><code>useReducer</code>는 상태를 관리할 때 사용가능한 hook 함수이고, 외부 컴포넌트에서 작성해 사용할 수 있다는 점이 useState와 다른점이다.</p>
<pre><code class="language-javascript">const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case &#39;increment&#39;:
      return {count: state.count + 1};
    case &#39;decrement&#39;:
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    &lt;&gt;
      Count: {state.count}
      &lt;button onClick={() =&gt; dispatch({type: &#39;decrement&#39;})}&gt;-&lt;/button&gt;
      &lt;button onClick={() =&gt; dispatch({type: &#39;increment&#39;})}&gt;+&lt;/button&gt;
    &lt;/&gt;
  );
}</code></pre>
<h3 id="usereducer의-사용법">useReducer의 사용법</h3>
<ul>
<li>reducer 함수<ul>
<li>state와 action을 인자로 받는다.<ul>
<li>state: 현재 상태</li>
<li>action: 업데이트를 위한 정보<ul>
<li>dispatch 함수</li>
<li>action을 실행시키는 함수이고, dispatch안에 action을 넣으면 reducer함수에서 action에 해당하는 정보로 state값을 업데이트 시킨다.</li>
<li>useReducer 함수</li>
<li>첫번째 인자에는 reducer 함수를 넣고, 두번째 인자에는 초기 state값을 넣는다.</li>
<li>결과값으로 state와 dispatch 함수를 받아온다.</li>
<li>state는 초기에는 두번째 인자에서 지정한 초기 state값으로 세팅되고, dispatch 함수 실행으로 reducer를 실행시켜 업데이트 된 값을 받아온다.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>📌 state 값이 변경될 때 새로운 state 값으로 대체(replace)되는 것이지 기존 state 값을 변경(modify)하거나 덮어쓰지(overwrite) 않는다. (데이터 불변성 유지)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[🥏 공식문서로 배우는 React]]></title>
            <link>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-we55x0md</link>
            <guid>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-we55x0md</guid>
            <pubDate>Tue, 23 Aug 2022 12:24:50 GMT</pubDate>
            <description><![CDATA[<h1 id="05-lifecycle">05. Lifecycle</h1>
<p>리액트에서 컴포넌트가 실행 될 때 컴포넌트에는 <strong>생성, 업데이트, 제거</strong> 동작의 생명주기를 가지게 된다.
<strong>생명주기(lifecycle) 메소드</strong>는 클래스형 컴포넌트에서 사용되며, 함수형 컴포넌트에서는 <strong>Hook</strong>을 사용한다.
생명주기 메소드와 Hook은 비슷하게 사용되지만 커버하지 않는 기능도 있고, 작동방식도 다르다.</p>
<blockquote>
<p>** React에서 랜더링이 실행되는 과정**</p>
</blockquote>
<ul>
<li>Props</li>
<li>State</li>
<li>forceUpdate()</li>
<li>부모 컴포넌트의 랜더링</li>
</ul>
<p>컴포넌트가 변경되는 여러 요인들과 상속하는 자식 컴포넌트 등 여러 이유로 불필요한 랜더링이 일어날 수 있는데, 불필요한 랜더링은 성능에 문제를 발생시킨다.</p>
<p><img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/2813ccc0-7cff-494c-8a20-6a4d598e64a4/image.png" alt=""></p>
<h2 id="the-component-lifecycle">The Component Lifecycle</h2>
<p>모든 컴포넌트는 여러 종류의 생명주기 메소드를 가지고 이 메소드들은 특정 시점에 실행하도록 설정해 줄 수 있다.</p>
<h3 id="mount">mount</h3>
<ul>
<li>constructor()<pre><code>: 컴포넌트의 생성자 메소드, 컴포넌트가 생성되면 가장 먼저 실행되는 메소드</code></pre></li>
</ul>
<pre><code class="language-javascript">constructor(props)</code></pre>
<ul>
<li>static getDerivedStateFromProps() <pre><code>:  props로 받아온 데이터를 ```state```에 넣어주고 싶을 때 사용한다. 
다른 메소드와 달리 ```static```이 필요하고, ```this```를 조회할 수 없다.
이 메소드에서 특정 객체를 반환하게 되면 해당 객체의 내용들이 ```state```로 설정되고, null을 반환하게 되면 아무 일도 발생하지 않는다.
컴포넌트가 처음 랜더링 되기 전과 리랜더링 되기 전에 매번 실행된다.</code></pre><pre><code class="language-javascript">static getDerivedStateFromProps(props, state)</code></pre>
<ul>
<li>render()
  : 컴포넌트를 랜더링하는 메소드<pre><code class="language-javascript">render()</code></pre>
</li>
<li>componentDidMount()
  : 컴포넌트의 첫번째 랜더링이 끝나면 호출되는 메소드이다.
  이 메소드가 호출 되었다는 것은 DOM이 화면에 다 그려진 상태이며, DOM을 연동해야하는 라이브러리나 데이터 요청(axios, fetch 등), DOM 속성을 읽거나 변경해야하는 작업을 할 수 있다.<pre><code class="language-javascript">componentDidMount()</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="update">update</h3>
<p>props나 state가 변경되면 갱신한다.</p>
<ul>
<li>static getDerivedStateFromProps()<pre><code>: 컴포넌트의 props나 state가 변경되었을 때 호출된다.</code></pre><pre><code class="language-javascript">static getDerivedStateFromProps(props, state)</code></pre>
</li>
<li>shouldComponentUpdate()<pre><code>: 컴포넌트가 리랜더링을 할지 결정하는 메소드이다. 
주로 최적화에 사용되며 React.memo와 역할이 비슷하다.
```forceUpdate()```는 ```shouldComponentUpdate```를 무시하고 랜더링 강행한다.</code></pre><pre><code class="language-javascript">shouldComponentUpdate(nextProps, nextState)</code></pre>
</li>
<li>render()</li>
<li>getSnapshotBeforeUpdate()<pre><code>: 컴포넌트에 변화가 일어나기 직전 DOM 상태를 가져와 특정 값을 반환하면 그다음 발생하게 되는 ```componenetDidUpdate()``` 함수에서 받아와 사용할 수 있다.</code></pre><pre><code class="language-javascript">getSnapshotBeforeUpdate(prevProps, prevState)</code></pre>
</li>
<li>componentDidUpdate()<pre><code>: 리랜더링이 마치고 화면에 원하는 변화가 반영된 후 호출되는 메소드이다.
세번째 파라미터로 ```getSnapshotBeforeUpdate```에서 반환한 값을 사용할 수 있다.</code></pre><pre><code class="language-javascript">componentDidUpdate(prevProps, prevState, snapshot)</code></pre>
</li>
</ul>
<h3 id="unmount">unmount</h3>
<p>컴포넌트가 DOM 상에서 제거될 때 호출된다.</p>
<ul>
<li>componentWillUnmount()<pre><code>: 컴포넌트가 화면에서 사라지기 직전에 호출된다.
여기서는 주로 DOM에 직접 등롱했던 이벤트를 제거하고 setTimeout 같은 함수를 사용했다면 clearTimeout을 사용해 제거해주는 역할을 한다.</code></pre><pre><code class="language-javascript">componentWillUnmount()</code></pre>
</li>
</ul>
<h2 id="other-apis">Other APIs</h2>
<p>위의 생명주기 메서드와 달리 아래의 메서드들은 사용자가 직접 컴포넌트 내에서 호출 할 수 있다.</p>
<h3 id="setstate">setState()</h3>
<ul>
<li>setState()는 컴포넌트를 갱신하는데 즉각적 명령이 아닌 요청이다.</li>
<li>리액트는 state의 변화를 즉시 적용하는 것을 보장하지 않는다.</li>
<li>여러 변경사항과 함꼐 일괄적으로 갱신하거나 나중으로 미룰 수 있다.</li>
<li><code>componentDidUpdate</code> 또는 <code>setState</code>의 콜백을 사용해 바로 값을 변경할 수 있다.</li>
<li><code>shouldComponentUpdate()</code>가 false를 반환하지 않는다면 <code>setState()</code>는 항상 랜더링을 발생시킨다.</li>
</ul>
<pre><code class="language-javascript">this.setState((state, props) =&gt; {
  return {counter: state.counter + props.step};
});</code></pre>
<ul>
<li>updater 함수로 전달된 state와 props는 최신값이 보장되고 state에 얕게 병합된다.</li>
</ul>
<h3 id="forceupdate">forceUpdate()</h3>
<ul>
<li>컴포넌트의 <code>state</code> 또는 <code>props</code>가 변경되면 컴포넌트가 리랜더링 되는 것이 기본 동작이다.</li>
<li><code>forceUpdate()</code>를 호출하면 <code>render()</code>가 호출되는데 shouldComponentUpdate()는 무시한다.</li>
<li>보통 <code>render()</code> 내에서는 <code>forceUpdate()</code>를 사용하지 말아야 하며, 오직 <code>this.props</code>와 <code>this.state</code>의 값만을 사용해야 한다.</li>
</ul>
<h2 id="참고">참고</h2>
<p><a href="https://reactjs.org/docs/react-component.html">https://reactjs.org/docs/react-component.html</a>
<a href="https://react.vlpt.us/basic/25-lifecycle.html">https://react.vlpt.us/basic/25-lifecycle.html</a>
<a href="https://velog.io/@sukong/REACT-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0%EC%99%80-useEffect-Hook">https://velog.io/@sukong/REACT-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0%EC%99%80-useEffect-Hook</a>
<a href="https://medium.com/vingle-tech-blog/react-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-f255d6569849">https://medium.com/vingle-tech-blog/react-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-f255d6569849</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] Heap]]></title>
            <link>https://velog.io/@sohyeonbak_oly/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Heap</link>
            <guid>https://velog.io/@sohyeonbak_oly/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Heap</guid>
            <pubDate>Sun, 21 Aug 2022 09:26:43 GMT</pubDate>
            <description><![CDATA[<p>Heap은 최소 노드 또는 최대 노드를 찾는 알고리즘이다.
트리구조를 가지기 때문에 노드가 있고, 부모노드와 자식노드의 연결구조와 비교를 통해 최대 힙, 최소 힙 구할 수 있다.
<br/></p>
<p><strong>Heap을 구성하기 위한 조건</strong></p>
<ol>
<li>완전이진트리</li>
<li>최대 힙일때는 부모노드 &gt; 자식노드, 최소 힙은 부모노드 &lt; 자식노드 이어야한다.</li>
</ol>
<h2 id="삽입-연산">삽입 연산</h2>
<p>heap에서 삽입연산을 실행할 때 주의해야 할 점은 노드의 위계가 변경되어서는 안된다.
새로운 노드를 추가한다면 마지막 노드에 임시로 저장 후 자신의 부모 노드와 비교하며 새로운 노드의 위치를 찾아가야한다.</p>
<p>아래 코드를 통해 확인 가능하다.</p>
<pre><code class="language-javascript">  exchange(a, b) {
    [ this.heap[a], this.heap[b] ] = [ this.heap[b], this.heap[a] ];
  }

  insert(data){ 
    this.heap.push(data); // 빈 배열 끝에 값을 넣는다. (노드 가장 마지막에 새 노드를 추가)
    let curIndex = this.heap.length - 1; // 배열의 가장 마지막 index가 추가된 값의 index (마지막 노드의 index) 
    let parIndex = Math.floor(curIndex / 2); // 추가된 인덱스 값의 부모 인덱스가 되는 값 (추가된 노드의 부모 노드)

    while(curIndex &gt; 1 &amp;&amp; this.heap[parIndex] &gt; this.heap[curIndex] ){ // curIndex가 1 이상이어야 부모노드가 있는 상태이고, 부모노드가 현재노드보다 클 때 해당 반복문이 실행된다.
      this.exchange(parIndex, curIndex); // 구조분해 할당을 통해 추가된 노드를 부모 노드와 변경해준다.(swap)

      curIndex = parIndex; // 현재노드를 부모노드와 바꿨기 때문에 바뀐 부모노드도 그 위의 부모노드와 비교해 값을 변경해줘야한다.
      parIndex = Math.floor(curIndex / 2); // 부모노드의 index값을 지정
    }
  }</code></pre>
<h2 id="삭제-연산">삭제 연산</h2>
<p>삭제 연산은 가장 작은 노드를 찾는 최소 힙이나 가장 큰 노드를 찾는 최대 힙 둘 다 최상위 노드(루트노드)가 그 값이 된다.
최상위 노드를 삭제하고 자식 노드를 비교해 최상위 노드로 위치를 옮겨줘야한다.
방법은 가장 마지막에 있는 노드를 최상위 노드로 옮겨 그 자식 노드들과 비교하며 위치를 조정한다.</p>
<p>아래 코드로 확인 가능하다.</p>
<pre><code class="language-javascript">delete() {
    const min = this.heap[1]; // 최상위 노드를 return
    if(this.heap.length &lt;= 2) this.heap = [ null ];
    else this.heap[1] = this.heap.pop();
  // if-else 구문은 해당 리스트의 사이즈를 확인해 최상위 노드 이외의 노드가 없다면 null처리를 해주기 위해 필요하다.

    let curIndex = 1; // 현재 노드의 index
    let leftIndex = curIndex * 2; // 왼쪽 자식의 index
    let rightIndex = curIndex * 2 + 1; // 오른쪽 자식의 index


    if(!this.heap[leftIndex]) return min  // heap은 완전이진트리 구조가 필수조건이기 때문에 왼쪽 자식이 없다면 오른쪽 자식도 없다. 그래서 바로 min 최소노드를 return 해줄 수 있다.
    if((!this.heap[rightIndex])) { // 오른쪽 노드만 없다면 왼쪽 노드와 현재 노드를 비교해 exchange해준다.
      if(this.heap[leftIndex] &lt; this.heap[curIndex]) {
        this.exchange(curIndex, leftIndex)
      }
      return min // exchange가 끝난 후 가장 노드를 Return 해준다.
    }

    while(this.heap[leftIndex] &lt; this.heap[curIndex] || this.heap[rightIndex] &lt; this.heap[curIndex]) { // 왼쪽 자식과 오른쪽 자식 둘 중 하나라도 현재 노드보다 작은 노드가 있다면 반복문을 실행한다.
      let minIndex = leftIndex &lt; rightIndex ? leftIndex : rightIndex; // 왼쪽과 오른쪽 노드 중 더 작은 노드의 index값을 찾는다.
      this.exchange(curIndex, minIndex) // 둘 중 더 작은 노드의 index와 현재 노드의 index를 비교해 exchange를 해준다.

      curIndex = minIndex; // 변경된 노드의 자식노드와의 비교를 위해 현재 노드를 자식 노드 중 가장 작은 노드의 index로 변경해준다.
      leftIndex = curIndex * 2; // 변경된 노드의 왼쪽 노드의 index
      rightIndex = curIndex * 2 + 1; // 변경된 노드의 오른쪽 index
    }

    return min // 처음 구했던 최상위 노드(루트 노드)를 리턴한다.
  }
}</code></pre>
<h2 id="heap-코드">Heap 코드</h2>
<pre><code class="language-javascript">class minHeap {
  constructor(){
    this.heap = [null];
  }

  size(){
    return this.heap.length - 1;
  }


  exchange(a, b) {
    [ this.heap[a], this.heap[b] ] = [ this.heap[b], this.heap[a] ];
  }

  insert(data){ 
    this.heap.push(data); // 빈 배열 끝에 값을 넣는다. (노드 가장 마지막에 새 노드를 추가)
    let curIndex = this.heap.length - 1; // 배열의 가장 마지막 index가 추가된 값의 index (마지막 노드의 index) 
    let parIndex = Math.floor(curIndex / 2); // 추가된 인덱스 값의 부모 인덱스가 되는 값 (추가된 노드의 부모 노드)

    while(curIndex &gt; 1 &amp;&amp; this.heap[parIndex] &gt; this.heap[curIndex] ){ // curIndex가 1 이상이어야 부모노드가 있는 상태이고, 부모노드가 현재노드보다 클 때 해당 반복문이 실행된다.
      this.exchange(parIndex, curIndex); // 구조분해 할당을 통해 추가된 노드를 부모 노드와 변경해준다.(swap)

      curIndex = parIndex; // 현재노드를 부모노드와 바꿨기 때문에 바뀐 부모노드도 그 위의 부모노드와 비교해 값을 변경해줘야한다.
      parIndex = Math.floor(curIndex / 2); // 부모노드의 index값을 지정
    }
  }

  delete() {
    const min = this.heap[1];
    if(this.heap.length &lt;= 2) this.heap = [ null ];
    else this.heap[1] = this.heap.pop();

    let curIndex = 1;
    let leftIndex = curIndex * 2;
    let rightIndex = curIndex * 2 + 1;


    if(!this.heap[leftIndex]) return min  
    if((!this.heap[rightIndex])) {
      if(this.heap[leftIndex] &lt; this.heap[curIndex]) {
        this.exchange(curIndex, leftIndex)
      }
      return min
    }

    while(this.heap[leftIndex] &lt; this.heap[curIndex] || this.heap[rightIndex] &lt; this.heap[curIndex]) {
      let minIndex = leftIndex &lt; rightIndex ? leftIndex : rightIndex;
      this.exchange(curIndex, minIndex)

      curIndex = minIndex;
      leftIndex = curIndex * 2;
      rightIndex = curIndex * 2 + 1;
    }

    return min
  }


}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[🥏 공식문서로 배우는 React]]></title>
            <link>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-hqjaf0sn</link>
            <guid>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-hqjaf0sn</guid>
            <pubDate>Thu, 18 Aug 2022 23:57:03 GMT</pubDate>
            <description><![CDATA[<h1 id="04-props-and-state">04. Props and State</h1>
<p>리액트에서 props와 state는 데이터를 다루는 개념이다.</p>
<blockquote>
<p> <strong>공식문서</strong>
props (“properties”의 줄임말) 와 state 는 일반 JavaScript 객체입니다. 
두 객체 모두 렌더링 결과물에 영향을 주는 정보를 갖고 있는데, 한 가지 중요한 방식에서 차이가 있습니다. 
props는 (함수 매개변수처럼) 컴포넌트에 전달되는 반면 state는 (함수 내에 선언된 변수처럼) 컴포넌트 안에서 관리됩니다.</p>
</blockquote>
<h2 id="props-are-read-only">Props are Read-Only</h2>
<p>Props는 부모 컴포넌트에서 자식 컴포넌트로 전달되는 데이터이다.
모든 리액트 컴포넌트는 자신의 props를 다룰 때 반드시 순수함수처럼 동작해야 한다.
순수 함수란 전달된 인자가 변경되지 않고 인자 그대로를 가지고 활용되는 것이다.</p>
<pre><code class="language-javascript">function sum(a, b) {
  return a + b;
}</code></pre>
<p>순수 함수는 입력값을 바꾸려하지 않고 동일한 입력값에 대한 결과를 반환한다.</p>
<pre><code class="language-javascript">function withdraw(account, amount) {
  account.total -= amount;
}</code></pre>
<p>반면 순수 함수가 아닐 경우에는 입력값을 변경하게 된다.</p>
<p>즉 전달된 데이터는 자식 컴포넌트에서 확인할 수 있지만 변경할 수는 없다.
컴포넌트에 속성처럼 데이터를 지정해 부모 컴포넌트에서 자식 컴포넌트로 데이터를 넘길 수 있다.</p>
<h2 id="using-state-correctly">Using State Correctly</h2>
<h3 id="직접-state를-수정하지-마세요">직접 state를 수정하지 마세요.</h3>
<pre><code class="language-javascript">// Wrong
this.state.comment = &#39;Hello&#39;;
// Correct
this.setState({comment: &#39;Hello&#39;});</code></pre>
<p><code>this.state</code>를 지정하는 곳은 오직 <code>constructor</code> 이다.</p>
<h3 id="state-업데이트는-비동기적일-수-있습니다">state 업데이트는 비동기적일 수 있습니다.</h3>
<p><code>this.props</code>와 <code>this.state</code>가 비동기적으로 업데이트될 수 있기 때문에 다음 state를 계산할 때 해당 값에 의존해서는 안된다.
state 값 자체를 의존하게 되면 비동기적인 호출에서 값을 제대로 가져올 수 없게 된다.</p>
<pre><code class="language-javascript">// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) =&gt; ({
  counter: state.counter + props.increment
}));</code></pre>
<p>함수 인자를 사용하는 <code>setState()</code>로 첫번째 인자는 이전 state를, 두번째 인자는 업데이트가 적용된 시점의 props로 받아 수정 가능하다.</p>
<h3 id="state-업데이트는-병합됩니다">state 업데이트는 병합됩니다.</h3>
<p>예를 들어, state에 다양한 독립적인 변수가 있다면 <code>setState()</code> 호출로 변수를 독립적으로 업데이트 할 수 있다.</p>
<pre><code class="language-javascript">  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

  componentDidMount() {
    fetchPosts().then(response =&gt; {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response =&gt; {
      this.setState({
        comments: response.comments
      });
    });
  }</code></pre>
<p>병합은 얕게 이뤄지기 때문에 <code>this.setState({comments})</code>는 <code>this.state.posts</code>에 영향을 주진 않지만 <code>this.state.comments</code>는 완전히 대체된다.</p>
<h2 id="the-data-flows-down">The Data Flows Down</h2>
<p>어떤 컴포넌트도 자신이 가진 데이터가 어디서 왔는지 알 필요가 없다.
오로지 state를 설정한 컴포넌트에서만 해당 state에 접근이 가능하고 자신의 state를 자식 컴포넌트에 props로 전달할 수 있다.
모든 state는 자신을 소유한 컴포넌트를 가지고 있고, 자신의 자식 컴포넌트에게만 영향을 끼칠 수 있다.
이것을 <strong>&quot;하향식(top-down)&quot;</strong> 또는 <strong>&quot;단방향식&quot;</strong> 데이터 흐름이라고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🥏 공식문서로 배우는 React]]></title>
            <link>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-hte4c0tk</link>
            <guid>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-hte4c0tk</guid>
            <pubDate>Tue, 16 Aug 2022 14:55:25 GMT</pubDate>
            <description><![CDATA[<h1 id="03-component">03. Component</h1>
<p>리액트에서 컴포넌트는 독립적이고 재사용 가능한 최소의 코드 단위이다.
자바스크립트의 함수와 같은 목적을 제공하지만 분리되어 동작하고 HTML을 return 해주는 특징을 가졌다.
컴포넌트의 이름은 항상 대문자로 시작해야한다.</p>
<h2 id="function-and-class-components">Function and Class Components</h2>
<p>컴포넌트는 함수형 컴포넌트와 클래스형 컴포넌트로 나뉜다.</p>
<ul>
<li>함수형 컴포넌트<ul>
<li>자바스크립트 함수를 작성한다.</li>
<li>export 하여 다른 파일에서 불러올 수 있도록 한다.</li>
</ul>
</li>
</ul>
<pre><code class="language-javascript">function Welcome(props) {
  return &lt;h1&gt;Hello, {props.name}&lt;/h1&gt;;
}</code></pre>
<ul>
<li>클래스형 컴포넌트<ul>
<li>컴포넌트 구성 요소와 리액트 생명주기를 모두 포함한다.</li>
<li>프로퍼티, state, 생명주기 함수가 필요한 구조에서 사용되는 컴포넌트다.<pre><code class="language-javascript">class Welcome extends React.Component {
render() {
return &lt;h1&gt;Hello, {this.props.name}&lt;/h1&gt;;
}
}</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="rendering-a-component">Rendering a Component</h2>
<pre><code class="language-javascript">const element = &lt;Welcome name=&quot;Sara&quot; /&gt;;</code></pre>
<p>리액트 엘리먼트로 DOM 태크 뿐만 아니라 사용자 정의 컴포넌트도 나타낼 수 있다.
리액트가 사용자 정의 컴포넌트로 작성한 엘리먼트를 만나면 작성된 요소를 객체로 만들어 전달해주는데 그것이 props가 된다.
props는 단일 객체로 요소를 key와 value 값으로 정의해 해당 컴포넌트에서 나타날 수 있게 된다.</p>
<pre><code class="language-javascript">function Welcome(props) {
  return &lt;h1&gt;Hello, {props.name}&lt;/h1&gt;;
}

const element = &lt;Welcome name=&quot;Sara&quot; /&gt;;
ReactDOM.render(
  element,
  document.getElementById(&#39;root&#39;)
);</code></pre>
<h3 id="📌-what-happens-in-this-example">📌 what happens in this example</h3>
<ul>
<li><code>&lt;Welcome name=&quot;Sara&quot; /&gt;</code> 엘리먼트로 <code>ReactDOM.render()</code>를 호출</li>
<li>React는 <code>{name: &#39;Sara&#39;}</code>를 props로 하여 Welcome 컴포넌트를 호출<ul>
<li>Welcom 컴포넌트에 작성된 요소를 props 단일 객체로 만들어 호출하게 된다.</li>
</ul>
</li>
<li>Welcome 컴포넌트는 결과적으로 <code>&lt;h1&gt;Hello, Sara&lt;/h1&gt;</code> 엘리먼트를 반환</li>
<li>React DOM은 <code>&lt;h1&gt;Hello, Sara&lt;/h1&gt;</code> 엘리먼트와 일치하도록 DOM을 효율적으로 업데이트</li>
</ul>
<h2 id="composing-components">Composing Components</h2>
<p>컴포넌트는 자신의 출력에 다른 컴포넌트를 참조해 사용할 수 있다.
컴포넌트에 다른 요소를 입력해 재사용이 가능하다.</p>
<pre><code class="language-javascript">function Welcome(props) {
  return &lt;h1&gt;Hello, {props.name}&lt;/h1&gt;;
}

function App() {
  return (
    &lt;div&gt;
      &lt;Welcome name=&quot;Sara&quot; /&gt;
      &lt;Welcome name=&quot;Cahal&quot; /&gt;
      &lt;Welcome name=&quot;Edite&quot; /&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h2 id="extracting-components">Extracting Components</h2>
<p>컴포넌트를 여러 작은 컴포넌트로 나누는 것은 큰 프로젝트에서 재사용 가능한 컴포넌트로 효율성을 높일 수 있다.
다음 코드를 작은 컴포넌트로 분리해보겠다.</p>
<pre><code class="language-javascript">function Comment(props) {
  return (
    &lt;div className=&quot;Comment&quot;&gt;
      &lt;div className=&quot;UserInfo&quot;&gt;
        &lt;img className=&quot;Avatar&quot;
          src={props.author.avatarUrl}
          alt={props.author.name}
        /&gt;
        &lt;div className=&quot;UserInfo-name&quot;&gt;
          {props.author.name}
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div className=&quot;Comment-text&quot;&gt;
        {props.text}
      &lt;/div&gt;
      &lt;div className=&quot;Comment-date&quot;&gt;
        {formatDate(props.date)}
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>이 컴포넌트는 props에 author(객체), text(문자열) 및 date(날짜)를 props로 받는다.
위 코드는 중첩구조로 변형하기 어렵고 재사용성도 높지 않아 보인다.
하지만 코드구조와 컴포넌트 분리로 가독성 높은 코드를 만들 수 있다.</p>
<pre><code class="language-javascript">function Avatar(props) {
  return (
    &lt;img className=&quot;Avatar&quot;
      src={props.user.avatarUrl}
      alt={props.user.name}
    /&gt;
  );
}

function UserInfo(props) {
  return (
    &lt;div className=&quot;UserInfo&quot;&gt;
      &lt;Avatar user={props.user} /&gt;
      &lt;div className=&quot;UserInfo-name&quot;&gt;
        {props.user.name}
      &lt;/div&gt;
    &lt;/div&gt;
  );
}


function Comment(props) {
  return (
    &lt;div className=&quot;Comment&quot;&gt;
      &lt;UserInfo user={props.author} /&gt; //분리한 컴포넌트 적용
      &lt;div className=&quot;Comment-text&quot;&gt;
        {props.text}
      &lt;/div&gt;
      &lt;div className=&quot;Comment-date&quot;&gt;
        {formatDate(props.date)}
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>Avatar 컴포넌트에서 props는 새롭게 key 값이 변경되었다.
props의 이름은 사용될 context가 아닌 컴포넌트 자체에서 어떤 역할을 하는지에 대한 관점으로 짓는것이 좋다.</p>
<h4 id="참고">참고</h4>
<p><a href="https://www.w3schools.com/react/react_components.asp">https://www.w3schools.com/react/react_components.asp</a>
<a href="https://goddaehee.tistory.com/299">https://goddaehee.tistory.com/299</a>
<a href="https://ko.reactjs.org/docs/components-and-props.html">https://ko.reactjs.org/docs/components-and-props.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🥏 공식문서로 배우는 React]]></title>
            <link>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-rkacqe9s</link>
            <guid>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React-rkacqe9s</guid>
            <pubDate>Thu, 11 Aug 2022 15:00:57 GMT</pubDate>
            <description><![CDATA[<h1 id="02-rendering-elements">02. Rendering Elements</h1>
<h2 id="react-dom">React-DOM</h2>
<p><strong>리엑트는 순수 자바스크립트</strong>이고, 자바스크립트를 이용해 컴포넌트들을 만들어 나간다.
브라우저는 HTML, CSS, JavaScript만을 읽을 수 있다.
리엑트는 결국 바벨을 이용해 자바스크립트로 변환되어지고 변환된 자바스크립트가 HTML과 연결시켜주는 것이 <strong>React-DOM</strong>이다.</p>
<h2 id="react-elements">React Elements</h2>
<p>리엑트 엘리먼트는 일반 객체(plain object)이며 쉽게 생성할 수 있다.
React DOM은 리엑트 엘리먼트와 DOM이 일치하도록 DOM을 업데이트 해주는 역할을 한다.</p>
<h2 id="rendering-an-element-into-the-dom">Rendering an Element into the DOM</h2>
<pre><code class="language-javascript">&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;</code></pre>
<p>리엑트로 구현된 어플리케이션은 일반적으로 하나의 루트 DOM 노드가 있다.
HTML 파일 어딘가에 <code>&lt;div&gt;</code> 태그가 있고, 이 안에 모든 엘리먼트를 React DOM에서 관리해서 <strong>루트(root) DOM 노드</strong>라고 한다.</p>
<pre><code class="language-javascript">const element = &lt;h1&gt;Hello, world&lt;/h1&gt;;
ReactDOM.render(element, document.getElementById(&#39;root&#39;));</code></pre>
<p>여러 리엑트 엘리먼트를 루트 DOM 노드에 렌더링하기 위해서 ReactDOM의 render 함수를 사용한다.</p>
<pre><code class="language-javascript">ReactDOM.render(element, container[, callback])</code></pre>
<p><code>element</code> 인자에는 리엑트에서 실행될 파일(App)을 넣어주고, <code>container</code>에 html파일에 작성된 id가 root인 요소를 넣어준다.
public폴더의 index.html 파일에 id가 root인 div 태그에 element인자인 리엑트 컴포넌트가 연결된다.</p>
<h2 id="updating-the-rendered-element">Updating the Rendered Element</h2>
<p>리엑트 엘리먼트는 불변객체이다.
그렇기 때문에 엘리먼트를 생성 후 자식이나 속성을 변경할 수 없다.
UI를 업데이트 하는 방법은 새로운 엘리먼트를 생성하고 다시 ReactDOM.render()로 전달하는 방법뿐이다.</p>
<blockquote>
<p>실제로 리엑트 앱은 ReactDOM.render()을 한 번만 호출한다.</p>
</blockquote>
<h2 id="react-only-updates-whats-necessary">React Only Updates What&#39;s Necessary</h2>
<p>React DOM은 해당 엘리먼트와 그 자식 엘리먼트를 이전의 엘리먼트와 비교해 DOM을 원하는 상태로 변경할 때 필요한 경우에만 DOM을 업데이트 한다.</p>
<p><img src="https://ko.reactjs.org/c158617ed7cc0eac8f58330e49e48224/granular-dom-updates.gif" alt=""></p>
<p>매초마다 UI를 다시 그리도록 function component로 jsx를 작성했으나 변경되는 시간만 업데이트 되는 것을 확인할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🥏 공식문서로 배우는 React]]></title>
            <link>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React</link>
            <guid>https://velog.io/@sohyeonbak_oly/%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-React</guid>
            <pubDate>Tue, 09 Aug 2022 15:25:44 GMT</pubDate>
            <description><![CDATA[<h1 id="01-introducing-jsx">01. Introducing JSX</h1>
<h2 id="overview">Overview</h2>
<pre><code class="language-javascript">const element = &lt;h1&gt;Hello, world!&lt;/h1&gt;;</code></pre>
<p>이것은 문자열도 HTML도 아닌 자바스크립트의 확장된 문법 <strong>JSX</strong>이다.
JSX를 통해 UI 로직을 설명해 줄 수 있기 때문에 리엑트와 함께 사용하는 것을 권장한다.</p>
<blockquote>
<h4 id="📌-jsx란">📌 JSX란</h4>
<p>리엑트에서 렌더링 로직이 UI로직과 연결된다는 사실을 받아들인다.
마크업와 비즈니스 로직을 분리하는 것이 아닌 &quot;컴포넌트&quot;라는 유닛으로 분리한다.
<strong>HTML처럼 생겼으나 마크업 언어가 아닌 자바스크립트 언어로 바벨로 변환이 되어지고, 비즈니스 로직을 작성할 수 있다.</strong></p>
</blockquote>
<h2 id="expressions-in-jsx">Expressions in JSX</h2>
<h3 id="특징-1">특징 1</h3>
<pre><code class="language-javascript">const name = &#39;Josh Perez&#39;;
const element = &lt;h1&gt;Hello, {name}&lt;/h1&gt;;</code></pre>
<pre><code class="language-javascript">function getGreeting(user) {
  if (user) {
    return &lt;h1&gt;Hello, {formatName(user)}!&lt;/h1&gt;;
  }
  return &lt;h1&gt;Hello, Stranger.&lt;/h1&gt;;
}</code></pre>
<p><strong>JSX는 중괄호 안에 모든 자바스크립트 표현식을 사용할 수 있다.</strong>
name이라는 변수에 할당된 값이 JSX에서 표현되어지고, if와 for문 등과 같은 자바스크립트 표현식을 모두 사용할 수 있다.</p>
<h3 id="특징-2">특징 2</h3>
<pre><code class="language-javascript">function NumberList(props) {
  const numbers = props.numbers;
  return (
    &lt;ul&gt;
      {numbers.map((number) =&gt;
        &lt;ListItem key={number.toString()}
                  value={number} /&gt;
      )}
    &lt;/ul&gt;
  );
}</code></pre>
<p>자바스크립트의 <code>map()</code>함수를 사용해 JSX를 반복적으로 호출해주는 방식이다.
해당 방식에서 주의해야 할 점은 <strong>Key를 설정해주는 것</strong>이다.
Key는 엘리먼트의 고유성을 부여하기 위해 반복문 안 엘리먼트에 지정해줘야하고, <code>&lt;li&gt;</code> 엘리먼트가 아니라 배열의 <code>&lt;ListItem /&gt;</code> 엘리먼트가 key를 가져야 한다.
Key는 형제 배열 안에서만 고유성을 지키면 되고, 전체 범위를 고려할 필요는 없다.</p>
<h3 id="특징-3">특징 3</h3>
<pre><code class="language-javascript">&lt;h1 className=&quot;title&quot; onClick={onload}&gt;Hello!!!&lt;/h1&gt;</code></pre>
<p>JSX는 자바스크립트와 가깝기 때문에 camelCase 프로퍼티로 사용해줘야 한다.
<code>* class → className</code>
<code>* tabindex → tabIndex</code>
<code>* onclick → onClick</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS 기초] 네트워크]]></title>
            <link>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-ajk0lbt6</link>
            <guid>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-ajk0lbt6</guid>
            <pubDate>Sun, 24 Jul 2022 23:19:49 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>&#39;성공과 실패를 결정하는 1%의 네트워크 원리&#39; 책을 바탕으로 정리한 내용입니다.</p>
</blockquote>
<h1 id="01케이블과-리피터-허브-속을-신호가-흘러간다">01.케이블과 리피터, 허브 속을 신호가 흘러간다</h1>
<h2 id="lan-케이블은-신호를-약화시키지-않는-것이-핵심이다">LAN 케이블은 신호를 약화시키지 않는 것이 핵심이다</h2>
<p>LAN 어댑터의 PHY회로에서 전기 신호로 형태를 바꾼 패킷은 RJ-45 커넥터를 통해 트위스트 페어 케이블에 들어간다.
이더넷의 신호의 실체는 플러스와 마이너스의 전압이므로 LAN 어댑터의 PHY 회로의 플러스와 마이너스 신호 단자에서 신호가 나온다.
PHY 회로는 RJ-45 커넥터에 직접 결선되어 있고 이 부분은 단순히 전기 신호가 케이블을 통해 전달 되는 것이다.
송신 신호 모습 그대로 허브에 도착하는 것이 아니라 허브에 도착할 때는 신호가 조금 약해져있다.</p>
<blockquote>
<p>케이블의 길이가 길어질수록 신호가 약해진다.
이더넷은 사각형의 각진 신호를 사용하지만 각이 뭉개져서 들어오게 된다.
주파수가 높을 수록 에너지가 떨어지는 비율이 높다는 전기 신호의 성질과 관계있다.</p>
</blockquote>
<h2 id="꼼은-잡음을-방지하기-위한-방법이다">&#39;꼼&#39;은 잡음을 방지하기 위한 방법이다</h2>
<h4 id="트위스트-페어-케이블꼰-선쌍">트위스트 페어 케이블(꼰 선쌍)</h4>
<p>: 두 가닥의 신호선을 한 조로 하여 마주 꼬았다는 데서 붙인 이름이고, 신호선을 마주 꼬아서 잡음을 막을 수 있다.</p>
<ul>
<li>잡음의 원인은 <strong>전자파</strong>
: 전자파가 금속 등의 도전체에 닿으면 그 안에 전류가 발생하는 성질이 있는데 신호와 잡음의 전류가 뒤섞여 신호의 파형이 변형되어 잡음이 생긴다.<ul>
<li>모터, 형광등, CRT 모니터와 같은 기기에서 누설되는 전자파
: 케이블 밖에서 오는 것이라 선을 꼼으로써 막을 수 있다.</li>
<li>케이블 안에 인접한 신호선에서 누설되는 전자파
: 신호선 안에 신호라는 전류가 흐르는데 이 전류 주위에 전자파가 생겨 잡음이 생기고 이러한 잡음을 <strong>크로스토크(crosstalk)</strong>
이러한 잡음을 잡는 것은 꼬는 간격을 일정하지 않게 해줌으로서 해결한다.</li>
</ul>
</li>
</ul>
<h2 id="리피터-허브는-연결되어-있는-전체-케이블에-신호를-송신한다">리피터 허브는 연결되어 있는 전체 케이블에 신호를 송신한다</h2>
<p>신호가 리피터 허브에 도달하면 LAN 전체에 신호가 흩어진다. 전체에 패킷의 신호를 뿌리고 수신처 MAC 주소에 해당하는 기기만 패킷을 수신하는 원리대로 리피터를 실현한 것이다.</p>
<ul>
<li>수신 방법은 &#39;송신 단자&#39;에서 보낸 신호를 &#39;수신 단자&#39;로 받게 해야한다.</li>
<li>리피터 허브 끝에 MDI/MDI-X와 같이 쓰여진 전환 스위치가 있다.<ul>
<li>MDI는 RJ-45 커넥터와 신호 송·수신 회로를 직접 결선한 것</li>
<li>MDI-X는 교차하여 결선하는 것</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS 기초] 네트워크]]></title>
            <link>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-6kl087cv</link>
            <guid>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-6kl087cv</guid>
            <pubDate>Wed, 20 Jul 2022 23:22:23 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>&#39;성공과 실패를 결정하는 1%의 네트워크 원리&#39; 책을 바탕으로 정리한 내용입니다.</p>
</blockquote>
<h1 id="05-ip와-이더넷의-패킷-송·수신-동작">05. IP와 이더넷의 패킷 송·수신 동작</h1>
<h2 id="패킷의-기본">패킷의 기본</h2>
<p>의뢰 받은 IP 담당 부분은 어떻게 패킷을 상대에게 송신할까?</p>
<ol>
<li>헤더와 데이터를 담은 패킷은 송신처가 되는 기기에서 만든다.</li>
<li>만들어진 패킷은 가장 가까운 중계 장치에 송신한다.</li>
<li>중계 장치는 도착한 패킷의 헤더를 조사해 패킷의 목적지를 판단한다.<ul>
<li>수신처가 어느 방향에 있는지에 대한 정보가 있는 표와 함께 목적지를 판단한다.</li>
</ul>
</li>
</ol>
<blockquote>
<p><code>엔드노드</code>는 송신처와 수신처를 명확하게 구별하지 않는 것을 묶어서 나타내는 것 </p>
</blockquote>
<h4 id="라우터와-허브">라우터와 허브</h4>
<ul>
<li>라우터가 목적지를 확인해 다음 라우터를 나타냄</li>
<li>허브가 서브넷 안에서 패킷을 운반해 다음 라우터에 도착</li>
</ul>
<ul>
<li>IP가 목적지를 확인해 다음 IP 중계장치를 나타냄 (허브-이더넷 규칙)</li>
<li>서브넷 안에 있는 이더넷이 중계장치까지 패킷을 운반 (라우터 - IP 규칙)</li>
</ul>
<ul>
<li>MAC 헤더(이더넷 용)</li>
<li>IP 헤더(IP 용)</li>
</ul>
<p>송신처에서 패킷의 목적지가 되는 엑세스 대상 서버의 IP 주소를 IP 헤더 수신처에 기록한다.
IP 수신처가 어느 방향에 있는지 조사하고 그 방향에 있는 라우터를 조사한다.
라우터에 패킷이 도착하도록 이더넷에 의뢰를 하고 다음 라우터에 이더넷의 주소를 조사해 그것을 MAC 헤더에 기록한다.</p>
<ul>
<li>이더넷의 헤더의 수신처 정보와 표를 결합해 패킷의 목적지를 판단해 중계한다.</li>
<li>라우터에는 IP용 표가 있어 이것과 IP 헤더의 수신처를 결합한다.</li>
</ul>
<h2 id="패킷의-송·수신-동작의-개요">패킷의 송·수신 동작의 개요</h2>
<ul>
<li>IP 헤더
: IP 프로토콜에 규정된 규칙에 따라 목적지까지 패킷을 전달할 때 사용되는 제어정보를 기록</li>
<li>MAC 헤더
: 이더넷 등 LAN을 사용해 가장 가까운 라우터까지 패킷을 운반할때 사용하는 정보를 기록</li>
</ul>
<p>패킷을 이제 LAN 어뎁터로 보내 줄 때 전기나 빛의 신호로 바뀌어 케이블에 송출된다.
신호는 허브나 라우터 등의 중계장치에 도착하고 중계장치가 상대 있는 곳까지 패킷을 전달한다.</p>
<h2 id="수신처-ip-주소를-기록한-ip-헤더를-만든다">수신처 IP 주소를 기록한 IP 헤더를 만든다</h2>
<p>IP 담당은 TCP에서 패킷 송·수신 의뢰를 받으면 IP 헤더를 만들어 TCP앞에 붙인다.</p>
<ul>
<li><p>수신처 IP 주소
: 패킷을 어디로 보내야하는지에 대한 정보</p>
<ul>
<li>TCP 담당 부분에서 통지된 상대 IP 주소를 설정</li>
<li>IP는 스스로 수신처를 판단하지 않고 지정한 상대에게 그대로 패킷을 송신한다.</li>
</ul>
</li>
<li><p>송신처 IP 주소
: IP 주소는 컴퓨터가 아닌 LAN 어댑터에 할당되어 LAN 어댑터를 장착하면 각 LAN 어댑터에 서로다른 IP 주소가 할당</p>
<ul>
<li>LAN 어댑터를 사용해 패킷을 송신해야하는지 판단한다</li>
</ul>
</li>
<li><p>IP 용 경로표
: IP 주소의 왼쪽부터 일치하는 것을 찾아낸다.</p>
<ul>
<li>Network Desination 항목</li>
<li>Interface는 어댑터 등의 네트워크용 인터페이스를 나타냄</li>
<li>Gateway는 다음 라우터의 IP 주소를 기록하게 되어 IP 주소를 가진 라우터에 패킷을 건네주면 라우터가 목적지에 패킷을 전달한다.</li>
</ul>
</li>
</ul>
<h2 id="이더넷용-mac-헤더를-만든다">이더넷용 MAC 헤더를 만든다</h2>
<p>이더넷에는 TCP/IP 개념이 통용되지 않는다.
MAC 헤더의 맨 앞에 있는 수신처 MAC 주소와 다음 송신처 MAC 주소는 각각 패킷을 전달하는 상대와 패킷을 송신한 송신처 MAC 주소를 나타낸다.</p>
<ul>
<li>이더타입(EitherType)
: IP 경우 IP 헤더 뒤에 이어지는 데이터가 어디에서 의뢰됐는지 프로토콜 번호에 기록되어 있고, 이더넷의 경우 MAC 헤더까지가 이더타입이다.<ul>
<li>0800</li>
<li>송신처 MAC 주소
: LAN 어댑터의 MAC 주소를 설정 ROM에 기록되어 있는 값을 읽어와서 MAC 헤더로 설정</li>
<li>수신처 MAC 주소
: 패킷을 건네주는 상대의 MAC 주소를 기록해 누구에게 건네줘야 할지 모르기 때문에 패킷을 줄 상대를 경로표로 조사해 Gateway항목에 기록되어 있는 IP 주소의 기기가 패킷을 건네줄 수 있다.</li>
</ul>
</li>
</ul>
<h2 id="arp로-수신처-라우터의-mac-주소를-조사한다">ARP로 수신처 라우터의 MAC 주소를 조사한다</h2>
<p>ARP(Address Resolution Protocol): 상대가 자신과 같은 네트워크에 존재하면 이것으로 MAC 주소를 알 수 있다. 그러면 MAC 주소를 MAC 헤더에 설정해 만들고 패킷을 보낼때마다 ARP의 패킷이 불어나서 한번 조사한 결과는 ARP 캐시라는 메모리 영역에 보존해 다시 사용하게된다.
ARP 캐시에 저장된 값은 시간이 지나면 삭제되게 되어있다.</p>
<ul>
<li>MAC 주소를 조사할 때는 ARP를 사용한다.<blockquote>
<p> 역할 분담을 획일적으로 해석해 IP 패킷만 취급할 수 있는 LAN 어댑터를 만드는 것보다 현실적으로 해석해 여러가지 패킷에 대응할 수 있는 LAN 어댑터를 만드는게 좋다.</p>
</blockquote>
</li>
</ul>
<h2 id="이더넷의-기본">이더넷의 기본</h2>
<p>이더넷 : 다수의 컴퓨터가 여러 상대와 자유롭게 적은 비용으로 통신하기 위해 고안된 기술</p>
<ul>
<li>트랜시버
: 연결한 케이블 사이에 신호를 흘리는 역할<ul>
<li>신호의 맨 앞부분에 수신처 주소를 써서 누구에게 갈 것인지 판단 할 수 있게 한다 </li>
</ul>
</li>
<li>이더타입으로 패킷의 내용물이 무엇이 들었는지 알 수 있다.<blockquote>
<p>전원에게 신호가 전달 된다는 성질은 변했고, 수신처 MAC 주소로 나타내는 원하는 기기가 존재하는 부분에만 신호가 흐르고, 다른 곳에는 신호가 흐르지 않게 된 것이다.</p>
</blockquote>
</li>
</ul>
<h2 id="ip-패킷을-전기나-빛의-신호로-변환해-송신한다">IP 패킷을 전기나 빛의 신호로 변환해 송신한다</h2>
<p>디지털데이터를 전기나 빛의 신호로 변환해 네트워크 케이블에 송출하는 것이 기본이다.</p>
<ul>
<li>LAN 어댑터
: 단독으로 동작하지 않고 제어를 위해 LAN 드라이버 소프트웨어가 필요<ul>
<li>LAN 드라이버가 하드웨어의 초기화 작업을 수행해 사용가능한 상태가 된다.</li>
<li>이더넷의 송·수신 동작을 제어하는 MAC이라는 회로에 MAC 주소를 설정하는 작업도 한다.
: LAN 어댑터의 ROM에는 중복되지 않도록 일원화해 관리하는 MAC 주소를 제조할 때 기록하기 때문에 MAC 회로에 설정한다.</li>
</ul>
</li>
</ul>
<h2 id="패킷에-3개의-제어용-데이터를-추가한다">패킷에 3개의 제어용 데이터를 추가한다</h2>
<p>MAC 회로는 <strong>프래앰블, 스타트 프레임 딜리미터</strong>라는 두개의 데이터와 <strong>프레임 체크 시퀀스(FCS)</strong> 라는 오류 검출용 데이터를 부가한다.
디지털 데이터를 전기 신호로 나타낼 때 0과 1의 비트값을 전압이나 전류 값에 대응한다.</p>
<ul>
<li>신호의 변화가 없어 비트 구분이 어려워지는 문제를 해결하기 위해 데이터를 나타내는 신호와 별도로 비트 구분을 나타내는 클록이라는 신호를 보내는 방법이 있다.
: 거리가 멀어져 케이블이 길어지면 신호선의 길이가 달라져서 데이터신호와 클록신호가 전달되는 시간에 차이가 생기면 이 방법도 문제가 생긴다.
: 변화의 타이밍까지 알고 수신한 신호에서 클록신호를 추출해 수신 신호와 클록 신호에서 원래 데이터 신호를 추출할 수 있게 된다.<ul>
<li>프리앰블
: 클록신호의 타이밍을 잡기 위해 특별한 신호를 패킷 앞에 부가</li>
</ul>
</li>
</ul>
<h2 id="허브를-향해-패킷을-송신한다">허브를 향해 패킷을 송신한다</h2>
<p>프리앰블, 스타트 프레임 딜리미터, PCS의 세가지를 부가하면 케이블에 송출하는 패킷이 완성된다.</p>
<ul>
<li>반이중 모드(리피터 허브를 사용)<ol>
<li>신호의 충돌을 피하기 위해 케이블에 다른 기기가 송신한 신호가 흐르는지 조사</li>
<li>신호가 흐르면 끝날때까지 기다리고 흐르지 않으면 송신 동작을 시작</li>
<li>송신 동작은 MAC 회로가 프리앰블의 맨 앞부터 1비트씩 차례로 디지털 데이터를 전기신호로 변환하고, PHY, MAU라는 송·수신 신호 부분으로 보낸다.<ul>
<li>PHY(MAU) 회로는 케이블에 송출하는 형식으로 변환해 송신
: MAC 회로에서 받은 신호를 케이블에 송신할 때 수신 신호선에 신호가 흘러들어오는지 감시</li>
</ul>
</li>
</ol>
</li>
<li>전이중 모드(스위칭 허브를 사용)</li>
</ul>
<h2 id="돌아온-패킷을-받는다">돌아온 패킷을 받는다</h2>
<ul>
<li>리피터 허브를 이용한 반이중 동작의 이더넷에서 1대가 송신한 신호가 리피터 허브에 접속된 케이블 전부에 흘러간다.</li>
<li>신호 맨 앞에 프리앰블로 파형에서 타이밍 계산하고, 스타트 프레임 딜리미터가 나오면 디지털 데이터로 변환해 동작을 개시한다.</li>
<li>PHY회로에서 MAC 회로로 진행 할 때 패킷의 맨 앞부터 계산식에 적용해 FCS 값을 개산하고 패킷의 끝의 PCS 값과 비교한다.</li>
<li>패킷 수신 사실을 <strong>인터럽트</strong> 구조를 사용해 통지한다.
: 컴퓨터 본체는 패킷이 도착한 사실을 알지 못해 컴퓨터 본체가 실행하는 있는 작업에 끼어들어 LAN 어댑터 쪽에 주위시키는 일을 한다.<ul>
<li>LAN 어댑터가 확장 버스 슬롯 부분에 인터럽트용 신호선에 신호를 보냄</li>
<li>신호가 흘러들어오면 CPU는 실행하던 작업을 보류하고 OS 내부의 인터럽트 처리용 프로그램으로 전환</li>
<li>인터럽트에는 번호가 자동으로 할당되어 LAN 어댑터가 인터럽트를 걸면 LAN 드라이버가 호출된다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS 기초]네트워크]]></title>
            <link>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC</link>
            <guid>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC</guid>
            <pubDate>Tue, 12 Jul 2022 23:34:33 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>&#39;성공과 실패를 결정하는 1%의 네트워크 원리&#39; 책을 바탕으로 정리한 내용입니다.</p>
</blockquote>
<h1 id="04-서버에서-연결을-끊어-소켓을-말소한다">04. 서버에서 연결을 끊어 소켓을 말소한다</h1>
<h2 id="데이터-보내기를-완료했을-때-연결을-끊는다">데이터 보내기를 완료했을 때 연결을 끊는다</h2>
<p>데이터 송·수신을 종료하는 것은 어플리케이션이 송신해야하는 데이터를 전부 송신 완료했다고 판단했을 때이다.
웹에서 송신을 완료한 측(웹 브라우저)에서 리퀘스트 메시지를 보내고 서버측이 연결 끊기 단계에 들어간다.
프로토콜 스택은 어느 쪽에서 먼저 연결 끊기 단계에 들어가도 좋게 만들어져 있다.</p>
<h3 id="연결을-끊는-단계">연결을 끊는 단계</h3>
<h4 id="서버→클라이언트">서버→클라이언트</h4>
<ol>
<li>데이터 보내기를 완료한 쪽(서버)에서 먼저 Socket 라이브러리의 close를 호출</li>
<li>서버측의 프로토콜 스택이 TCP 헤더를 만들고 연결끊기를 나타내는 정보를 설정<ul>
<li>컨트롤 비트의 FIN 비트에 1을 설정</li>
</ul>
</li>
<li>IP 담당 부분에 의뢰해 클라이언트에 송신해 달라고 요청</li>
</ol>
<h4 id="클라이언트→서버">클라이언트→서버</h4>
<ol>
<li>서버에서 FIN에 1을 설정한 TCP 헤더가 도착하면 클라이언트 측의 프로토콜 스택은 자신의 소켓에 서버측이 연결 끊기 동작에 들어갔다는 것을 기록</li>
<li>FIN을 1로 받았다는 것을 알리기 위해 ACK 번호를 서버측에 반송</li>
<li>데이터가 올 때까지 기다렸다가 어플리케이션이 read를 호출해 데이터를 가져옴</li>
<li>데이터를 건네지 않고 서버에서 보낸 데이터를 전부 수신 완료했다는 사실을 어플리케이션에 알림</li>
<li>서버에 보낸 데이터를 전부 수신 완료하면 클라이언트도 종료</li>
<li>클라이언트 어플리케이션도 close를 호출해 작업을 끝낸다.</li>
<li>클라이언트 측 프로토콜 스택은 FIN 비트에 1을 설정한 TCP 헤더를 만들고 IP 담당 부분에 의뢰해 서버에 송신 후 ACK 번호가 들어오면 서버와의 대화를 끝낸다.</li>
</ol>
<h2 id="소켓을-말소한다">소켓을 말소한다</h2>
<p>서버와의 대화가 끝나면 소켓을 사용해 서버와 대화할 수 없게 된다.
바로 말소 하지 않고 오작동을 막기 위해 잠시 기다린다.</p>
<h2 id="데이터-송·수신-동작을-정리한다">데이터 송·수신 동작을 정리한다</h2>
<h4 id="접속-동장">접속 동장</h4>
<ol>
<li>소켓을 작성하는 단계
: 서버측에서 애플리케이션이 동작하기 시작했을 때 소켓을 만들고 이것을 접속 대기 상태로 만든다.<ul>
<li>클라이언트 측은 서버에 엑세스 하는 동작을 시작할 때 패킷을 작성
: 패킷을 주고받지는 않는다.</li>
</ul>
</li>
<li>접속 동작 실행
: 클라이언트가 SYN을 1로 만든 TCP 헤더를 만들어 서버에 보냄<ul>
<li>TCP 헤더에는 시퀀스 번호의 초기값도 기록</li>
<li>데이터 송신에 사용하는 윈도우 값도 기록</li>
</ul>
</li>
<li>서버에서 SYN을 1로 만든 헤더를 받음</li>
<li>서버에서 다시 ACK 번호와 시퀀스 번호의 초기값, 윈도우, SYN을 1로 한 값을 기록해 클라이언트로 보냄</li>
<li>클라이언트는 받은 정보를 ACK 번호를 기록한 TCP 헤더를 서버로 보낸다.</li>
</ol>
<h4 id="데이터-송·수신-단계">데이터 송·수신 단계</h4>
<ol>
<li>클라이언트에서 서버에 리퀘스트 메세지 전송</li>
<li>TCP는 적당한 크기 조각으로 분할</li>
<li>TCP 헤더를 앞에 부가해 서버에 전송<ul>
<li>송신 데이터가 몇 번째 바이트부터 시작되는지 나타내는 시퀀스 번호 기록</li>
</ul>
</li>
<li>서버는 ACK 번호를 클라이언트에 반송<ul>
<li>최초 데이터는 받기만 하지만, 데이터 송·수신 중 애플리케이션에 데이터를 건네 수신 버퍼에 빈 영역이 생기면 윈도우 값도 기록해 클라이언트에 통지</li>
</ul>
</li>
<li>서버에서 응답 메세지 반송</li>
</ol>
<h4 id="연결-끊기-동작">연결 끊기 동작</h4>
<ol>
<li>서버에서 응답 메세지 보내기를 완료하면 FIN을 1로 만든 TCP 헤더가 흐른다.</li>
<li>이것을 받았음을 나타내는 ACK번호의 TCP 헤더가 돌아온다.</li>
<li>역방향으로 한번 더 진행 후 소켓이 말소 된다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS 기초] 운영체제]]></title>
            <link>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-86eoku05</link>
            <guid>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-86eoku05</guid>
            <pubDate>Sun, 10 Jul 2022 15:27:27 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>&#39;운영체제와 정보기술의 원리&#39; 책을 바탕으로 정리한 내용입니다.</p>
</blockquote>
<h1 id="06-cpu-스케줄링">06. CPU 스케줄링</h1>
<p>CPU는 프로그램의 기계어 명령을 실제로 수행하는 컴퓨터 내의 중앙처리장치이다.
기계어 명령은 크게 <strong>CPU 내에서 수행되는 명령, 메모리 접근을 필요로 하는 명령, 입출력을 동반하는 명령</strong>으로 나뉜다.</p>
<h4 id="cpu-내에서-수행되는-명령">CPU 내에서 수행되는 명령</h4>
<ul>
<li>add 명령 : CPU 내에 레지스터에 있는 두 값을 더해 레지스터에 저장하는 명령<h4 id="메모리-접근을-필요로-하는-명령">메모리 접근을 필요로 하는 명령</h4>
</li>
<li>load 명령 : 메모리에 있는 데이터를 CPU로 읽어들이는 명령</li>
<li>store 명령 : CPU에서 계산된 결괏값을 메모리에 저장하는 명령
→ CPU내에서 수행되는 명령보다는 시간이 오래 소요되지만 비교적 짧은 시간에 수행할 수 있는 명령</li>
</ul>
<blockquote>
<p>두 명령은 사용자 프로그램이 직접 수행할 수 있는 <strong>일반명령</strong>이다.</p>
</blockquote>
<h4 id="입출력을-동반하는-명령">입출력을 동반하는 명령</h4>
<p>다른 두 명령에 비해 오랜 시간이 소요된다.</p>
<blockquote>
<p>모든 입출력 명령을 <strong>특권명령</strong>으로 규정해 사용자 프로그램이 직접 수행할 수 없도록 하고 운영체제를 통해 서비스를 대행한다</p>
</blockquote>
<h4 id="사용자-프로그램이-수행되는-과정은-cpu작업과-io-작업의-반복">사용자 프로그램이 수행되는 과정은 CPU작업과 I/O 작업의 반복</h4>
<p>서로 다른 두 단계의 조합으로 프로그램 수행은 이뤄진다.</p>
<ul>
<li>CPU 버스트
  : 사용자 프로그램이 CPU를 직접 가지고 빠른 명령을 수행하는 단계<ul>
<li>프로그램이 I/O를 한 번 수행한 후 다음 번 I/O를 수행하기까지 직접 CPU를 가지고 명령을 수행</li>
</ul>
</li>
<li>I/O 버스트
  : I/O 요청이 발생해 커널에 의해 입출력 작업을 진행하는 비교적 느린 단계<ul>
<li>I/O 작업이 요청 된 후 다시 CPU 버스트로 돌아가기까지 일어나는 일련의 작업</li>
</ul>
</li>
</ul>
<p>각 프로그램 마다 CPU 버스트와 I/O 버스트가 차지하는 비율이 균일하지 않다.</p>
<ul>
<li>I/O 바운드 프로세스
: I/O 요청이 빈번해 CPU 버스트가 짧게 나타나는 프로세스<ul>
<li>인터렉션을 계속 받는 대화형 프로그램</li>
<li>짧은  CPU 버스트를 많이 가짐</li>
</ul>
</li>
<li>CPU 바운드 프로세스
: I/O 작업을 거의 수행하지 않아 CPU 버스트가 길게 나타나는 프로세스<ul>
<li>상당 시간을 입출력 작업 없이 CPU 작업에 소모하는 계산 위주의 프로그램</li>
<li>소수의 긴 CPU 버스트로 구성</li>
</ul>
</li>
</ul>
<p>→ 시분할 시스템에서는 CPU 버스트가 균일하지 않은 다양한 프로그램들이 공존하므로 효율적인 CPU 스케줄링 기법이 필요
: CPU 스케줄링 시 I/O 바운드 프로세스의 우선순위를 높여주는 것이 바람직</p>
<h2 id="cpu-스케줄러">CPU 스케줄러</h2>
<p>CPU 스케줄러는 준비 상태에 있는 프로세스들 중 어떠한 프로세스에게 CPU를 할당할지 결정하는 운영체제.
프로세스가 CPU를 할당받고 기계어 명령을 수행하다가 타이머 인터럽트가 발생하면 CPU 스케줄러가 호출된다.</p>
<h4 id="cpu-스케줄러가-필요한-경우">CPU 스케줄러가 필요한 경우</h4>
<ol>
<li>실행 상태에 있던 프로세스가 I/O 요청으로 봉쇄 상태로 바뀌는 경우</li>
<li>실행 상태에 있던 프로세스가 타이머 인터럽트 발생에 의해 준비 상태로 바뀌는 경우</li>
<li>I/O 요청으로 봉쇄 상태에 있던 프로세스의 I/O 작업이 완료되어 인터럽트가 발생하고 그 결과 프로세스의 상태가 준비 상태로 바뀌는 경우</li>
<li>CPU에서 실행 상태에 있는 프로세스가 종료되는 경우</li>
</ol>
<h4 id="cpu-스케줄링-방식">CPU 스케줄링 방식</h4>
<ul>
<li>비선점형 방식
: CPU를 획득한 프로세스가 스스로 CPU를 반납하기 전까지는 CPU를 빼앗기지 않는 방법</li>
<li>선점형 방식
: 프로세스가 CPU를 계속 사용하기를 원하더라도 강제로 빼앗을 수 있는 방식<ul>
<li>할당시간을 부여해 타이머 인터럽트를 발생</li>
</ul>
</li>
</ul>
<h2 id="디스패처">디스패처</h2>
<p>새롭게 선택된 프로세스가 CPU를 할당받고 작업을 수행할 수 있도록 환경설정을 하는 운영체제 코드</p>
<ul>
<li>수행 중이던 프로세스의 문맥을 그 프로세스의 PCB에 저장</li>
<li>새롭게 선택된 프로세스의 문맥을 PCB로 부터 복원</li>
<li>해당 프로스세에게 CPU를 넘기는 과정을 수행</li>
<li>복원 후 시스템의 상태를 사용자모드로 전환해 사용자 프로그램에게 CPU의 제어권을 넘긴다.</li>
</ul>
<h2 id="스케줄링의-성능-평가">스케줄링의 성능 평가</h2>
<ul>
<li>시스템 관점의 지표<ul>
<li>CPU 이용률
: 전체 시간 중 CPU가 일을 한 시간의 비율</li>
<li>처리량
: 주어진 시간 동안 준비 큐에서 기다리고 있는 프로세스 중 몇개를 끝마쳤는지 나타내는 것</li>
</ul>
</li>
<li>사용자 관점의 지표<ul>
<li>소요시간
: 프로세스가 CPU를 요청한 시점부터 자신이 원하는 만큼 CPU를 다 쓰고 CPU 버스트가 끝날 때까지 걸린 시간</li>
<li>대기시간
: CPU 버스트 기간 중 프로세스가 준비 큐에서 CPU를 얻기 위해 기다린 시간의 합</li>
<li>응답시간
: 프로세스가 준비 큐에 들어온 후 첫번째 CPU를 획득하기까지 기다린 시간</li>
</ul>
</li>
</ul>
<h2 id="스케줄링-알고리즘">스케줄링 알고리즘</h2>
<h3 id="1-선입선출-스케줄링">1. 선입선출 스케줄링</h3>
<p>프로세스가 준비 큐에 도착한 시간 순서대로 CPU를 할당하는 방식.</p>
<ul>
<li>먼저 도착한 프로셋의 성격에 따라 평균 대기시간이 크게 달라진다.</li>
</ul>
<h3 id="2-최단작업-우선-스케줄링">2. 최단작업 우선 스케줄링</h3>
<p>CPU 버스트가 가장 짧은 프로세스에게 제일 먼저 CPU를 할당하는 방식</p>
<ul>
<li>평균 대기시간을 가장 짧게 하는 최적 알고리즘</li>
<li>비선점형 방식
: 현재 CPU를 점유하고 있는 프로세스가 CPu 버스트를 모두 수행하고 스스로 CPU 버스트를 내어놓을 때까지 스케줄링 하지 않는다.</li>
<li>선점형 방식
: CPU 버스트 시간이 더 짧은 프로세스가 도착하면 현재 수행 중인 프로세스에게서 CPU를 선점해 CPU 버스트 시간이 더 짧은 프로세스에게 할당
→ 현실적으로 어려운 점은 CPU 버스트 시간을 미리 알 수 없음</li>
</ul>
<h3 id="3-우선순위-스케줄링">3. 우선순위 스케줄링</h3>
<p>준비 큐에서 기다리는 프로세스들 중 우선순위가 가장 높은 프로세스에게 제일 먼저 CPU를 할당하는 방식</p>
<ul>
<li>우선순위값
: 우선순위값이 작을수록 높은 우선순위를 가지는 것으로 가정</li>
<li>비선점형 방식
: 일단 CPU를 얻었으면 비록 우선순위가 더 높은 프로세스더라도 CPU를 자진 반납하기 전까지 선점하지 않는다</li>
<li>선점형 방식
: CPU에서 수행 중인 프로세스보다 우선순위가 높은 프로세스가 도착하여 CPU를 선점해 새롭게 도착한 프로세스에게 할당하는 경우</li>
</ul>
<h4 id="기아현상">기아현상</h4>
<p>우선순위가 높은 프로세스가 계속 도착하는 상황에서 우선순위가 낮은 프로세스는 CPU를 얻지 못한 채 계속 기다리게 되는 현상</p>
<ul>
<li>노화기법
: 기다리는 시간이 길어지면 우선순위를 조금씩 높여 언젠가는 가장 높은 우선순위가 되어 CPU를 할당 받을 수 있게 하는 방법</li>
</ul>
<h3 id="4-라운드-로빈-스케줄링">4. 라운드 로빈 스케줄링</h3>
<p>시분할 시스템의 성질을 가장 잘 활용한 새로운 의미의 스케줄링 방식</p>
<ul>
<li>시간이 경과하면 해당 프로세스로부터 CPU를 회수해 준비 큐에 줄 서 있는 다른 프로세스에게 CPU를 할당</li>
<li>이 프로세스의 준비 큐의 제일 뒤에 가서 줄을 서 다음번 차례가 오기를 기다림</li>
<li>각 프로세스마다 한 번에 CPU를 연속적으로 사용할 수 있는 최대시간을 <strong>할당시간</strong>이라고 한다.
→ 여러 이질적인 프로세스가 같이 실행되는 환경에서 효과적이다.
모든 프로세스는 (n-1)q시간 내에 적어도 한 번은 CPU를 할당받을 수 있다.</li>
<li>SJF 방식보다 평균 대기 시간은 길지만 응답시간은 더 짧다.</li>
<li>할당시간이 만료되어 CPU를 회수하는 방법으로 쓰인다.</li>
</ul>
<blockquote>
<h4 id="라운드-로빈의-목적">라운드 로빈의 목적</h4>
<p>: CPU 버스트 시간이 짧은 프로세스가 빨리 CPU를 얻을 수 있도록 하는 동시에 CPU 버스트 시간이 긴 프로세스가 불이익을 당하지 않도록 하는 것</p>
</blockquote>
<ul>
<li>할당시간을 너무 짧게 설정하면 문맥교환의 오버헤드가 증가해 전체 시스템의 성능을 저하시킬 수 있다.</li>
<li>프로세스를 하나씩 끝내는 식으로 시간이 흐름에 따라 적어도 하나씩은 처리가 완료된 프로세스가 발생해 평균대기시간이나 소요시간 측면에서 좋은 결과를 얻을 수 있다.</li>
</ul>
<h3 id="5-멀티레벨-큐">5. 멀티레벨 큐</h3>
<p>준비 큐를 여러개로 분할해 관리하는 스케줄링 기법</p>
<ul>
<li>한 줄이 아닌 여러 줄로 서는 것</li>
<li>일반적으로 성격이 다른 프로세스들을 별도로 관리하고, 프로세스의 성격에 맞는 스케줄링을 적용하기 위해 준비 큐를 별도로 두게 된다.</li>
<li>전위 큐
: 대화형 작업을 담기 위한 것<ul>
<li>응답시간을 짧게 하기 위해 라운드로빈 스케줄링을 사용</li>
</ul>
</li>
<li>후위 큐
: 계산 위주의 작업을 담기 위한 것<ul>
<li>응답시간이 큰 의미가 없기 때문에 FCFS 스케줄링기법을 사용해 문맥교환 오버헤드를 줄인다.</li>
</ul>
</li>
<li>고정 우선순위 방식
: 고정적인 우선순위를 부여해 우선순위가 높은 큐를 먼저 서비스하고 우선순위가 낮은 큐는 우선순위가 높은 큐가 비어있을 때만 서비스</li>
<li>타임 슬라이스 방식
: 큐에 대한 기아 현상을 해소할 수 있는 방식으로, 각 큐에 CPU 시간을 적절할 비율로 할당</li>
</ul>
<h3 id="6-멀티레벨-피드백-큐">6. 멀티레벨 피드백 큐</h3>
<p>CPU를 기다리는 프로세스를 여러 큐에 줄 세운다는 측면에서 멀티레벨 큐와 동일하나, 프로세스가 하나의 큐에서 다른 큐로 이동 가능하다는 점이 다르다.</p>
<blockquote>
<h4 id="멀티레벨--피드백-큐-정의-요소">멀티레벨  피드백 큐 정의 요소</h4>
</blockquote>
<ul>
<li><p>큐의 수</p>
</li>
<li><p>큐의 스케줄링 알고리즘</p>
</li>
<li><p>프로세스를 상위 큐로 승격시키는 기준</p>
</li>
<li><p>프로세스를 하위 큐로 강등시키는 기준</p>
</li>
<li><p>프로세스가 도착했을 때 들어갈 큐를 결정하는 기준</p>
</li>
<li><p>스케줄링 방식으로 최상위 큐가 우선적으로 CPU를 배당받고, 상위 큐가 비었을 때 하위 큐에 프로세스들이 CPU를 할당 받을 수 있게 한다.</p>
</li>
</ul>
<h3 id="7-다중처리기-스케줄링">7. 다중처리기 스케줄링</h3>
<p>CPU가 여러 개인 시스템을 다중처리기 시스템이라하고 이런 환경에서 프로세스를 준비 큐에 한 줄로 세워 각 CPU가 알아서 다음 프로세스를 꺼내가도록 한다.</p>
<ul>
<li>반드시 특정 CPU에서 수행되어야하는 프로세스가 있는 경우 한 줄 이 아니라 각 CPU 별로 줄세우기를 할 수도 있다.</li>
<li><strong>부하균형 메커니즘</strong> 필요
: CPU 별 부하가 적절히 분산되도록 한다.</li>
<li>대칭형 다중처리
: 각 CPU가 알아서 스케줄링을 결정</li>
<li>비대칭형 다중처리
: 하나의 CPU가 다른 모든 CPU의 스케줄링 및 데이터 접근을 책임지고 나머지 CPU는 거기에 따라 움직임</li>
</ul>
<h3 id="8-실시간-스케줄링">8. 실시간 스케줄링</h3>
<ul>
<li>경성 실시간 시스템
: 정확히 시간을 지켜야하는 시스템</li>
<li>연성 실시간 시스템
: 데드라인이 존재하지만 못지켰다고 큰일이 나지는 않는 시스템</li>
</ul>
<h2 id="스케줄링-알고리즘의-평가">스케줄링 알고리즘의 평가</h2>
<ul>
<li>큐잉모델
: 이론가들이 수행하는 방식으로 확률분포를 통해 프로세스들의 도착률과 CPU의 처리율을 입력값으로 성능지표인 CPU의 처리량과 대기시간을 구하는 것</li>
<li>시뮬레이션
: 가상으로 CPU 스케줄링 프로그램을 작성한 후 프로그램의 CPU 요청을 입력값으로 넣어 결과값을 확인 하는 것</li>
<li>규현 및 실측
: 운영체제 커널의 소스 코드 중 CPU스케줄링을 수행하는 코드를 수정해 컴파일 후 시스템에 설치하는 과정</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS 기초] 운영체제]]></title>
            <link>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C</link>
            <guid>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C</guid>
            <pubDate>Sat, 02 Jul 2022 14:20:16 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>&#39;운영체제와 정보기술의 원리&#39; 책을 바탕으로 정리한 내용입니다.</p>
</blockquote>
<h1 id="05-프로세스-관리">05. 프로세스 관리</h1>
<h2 id="프로세스의-개념">프로세스의 개념</h2>
<p><strong>프로세스</strong>(≒job)란 실행 중인 프로그램(program in execution)을 뜻하고 디스크에 실행파일 형태로 존재하던 프로그램이 메모리에 올라가서 실행되는 것이다.</p>
<p><strong>프로세스 문맥</strong>은 프로세스가 현재 어떤 상태에서 수행되고 있는지 정확히 규명하기 위해 필요한 정보를 의미한다.
여러 프로세스가 함께 수행되는 시분할 시스템 환경에서는 타이머 인터럽트에 의해 짧은 시간 동안 CPU를 사용한 후 빼앗겼다가 추후에 다시 CPU를 획득하는 식으로 관리된다.
→ 정확한 재현을 위해 필요한 정보이다.</p>
<ul>
<li>하드웨어 문맥
  : CPU의 수행 상태를 나타내는 것<ul>
<li>프로그램 카운터 값</li>
<li>각종 레지스터에 저장하고 있는 값</li>
<li>주소 공간(코드, 데이터, 스택 상태)</li>
<li>PCB와 커널스택
: 프로세스 상태가 되면 운영체제는 프로세스를 관리하기 위한 자료구조를 유지</li>
</ul>
</li>
</ul>
<h2 id="프로세스의-상태">프로세스의 상태</h2>
<p>프로세스의 상태는 실행(running), 준비(ready), 봉쇄(block, wait, sleep)으로 구분할 수 있다.</p>
<ul>
<li>실행 상태
: 프로세스가 CPU를 보유하고, 기계어 명령을 실행하고 있는 상태를 가리킨다.</li>
<li>준비 상태
: 프로세스가 CPU만 보유하면 당장 명령을 실행 할 수 있지만 CPU를 할당받지 못한 상태</li>
<li>봉쇄 상태
: CPU를 할당받더라도 당장 명령을 실행할 수 없는 프로세스의 상태</li>
<li>시작 상태
: 프로세스가 생성</li>
<li>완료 상태
: 프로세스가 종료중인 일시적 상태
→ 컴퓨터 자원을 효율적으로 관리하기 위해서</li>
</ul>
<h4 id="문맥교환">문맥교환</h4>
<p>: 실행시킬 프로세스를 변경하기 위해 원래 수행중이던 프로세스의 문맥을 저장하고 새로운 프로세스의 문맥을 세팅하는 과정</p>
<ul>
<li>타이머 인터럽트가 발생하는 경우</li>
<li>실행 상태에 있던 프로세스가 입출력 요청등으로 봉쇄 상태로 바뀌는 경우
→ CPU를 할당받을 프로세스를 선택한 후 실제로 CPU의 제어권을 넘겨받는 과정을 <strong>CPU 디스패치</strong></li>
</ul>
<h2 id="프로세스-제어블록">프로세스 제어블록</h2>
<p>프로세스 제어블록(Process Control Block: PCB)는 운영체제가 시스템 내의 프로세스들을 관리하기 위해 프로세스마다 유지하는 정보들을 담는 커널 내의 자료구조</p>
<ul>
<li>프로세스의 상태
: CPU를 할당해도 되는지 여부 결정</li>
<li>프로그램 카운터의 값
: 다음에 수행할 명령의 위치를 가리킴</li>
<li>CPU 레지스터의 값
: CPU 연산을 위해 현 시점에 레지스터의 어떤 값을 저장하고 있는지 나타냄</li>
<li>CPU 스케쥴링 정보
: 프로세스의 CPU 스케줄링을 위해 필요한 정보</li>
<li>메모리 관리 정보
: 프로세스의 메모리 할당을 위해 필요한 정보</li>
<li>자원 사용 정보
: 사용자에게 자원 사용 요금을 계산해 청구하는 등</li>
<li>입출력 상태 정보
: 프로세스가 오픈한 파일 정보 등 프로세스의 입출력 관련 정보 </li>
</ul>
<h2 id="문맥교환-1">문맥교환</h2>
<p><strong>문맥교환</strong>은 하나의 사용자 프로세스로부터 다른 사용자 프로세스로 CPU의 제어권이 이양되는 과정이다.</p>
<p>이양 되는 과정에서 원래 수행중이던 프로세스는 준비 상태로 바뀌고 새롭게 CPU를 할당받은 프로세스는 실행 상태가 된다.</p>
<p>프로세스가 실행 상태일 때 시스템 콜이나 인터럽트가 발생하면 CPU의 제어권이 운영체제로 넘어와 원래 실행 중이던 프로세스의 업무를 잠시 멈추고 커널의 코드가 실행된다.</p>
<p>사용자모드에서 커널모드로 바뀌어 시스템 콜이나 인터럽트 처리를 하고, 다시 동일한 프로셋의 사용자모드로 돌아와 이전에 수행하던 작업을 계속 수행한다.</p>
<h2 id="프로세스를-스케줄링하기-위한-큐">프로세스를 스케줄링하기 위한 큐</h2>
<p>운영체제는 준비상태에 있는 프로세스들을 줄 세우기 위해 준비 큐(ready queue)를 두고 준비 큐의 제일 앞에 줄 서 있는 프로세스에 제일 먼저 CPU를 할당한다.
운영체제는 CPU 뿐만아니라 특정 자원을 기다리는 프로세스들을 줄 세우기 위해 자원별로 장치 큐(device queue)를 둔다.</p>
<ul>
<li>디스크 입출력 큐
→ 디스크 컨트롤러는 디스크 입출력 큐에 줄 서 있는 순서대로 프로세스들의 입출력 작업을 수행
→ 작업이 끝나면 디스크 컨트롤러가 CPU에 인터럽트를 발생
→ 인터럽트 처리루틴에 의해 디스크 입출력이 완료된 프로세스는 입출력 큐에서 빠져나와 CPU를 기다리는 준비 큐에 줄을 서게 된다.</li>
</ul>
<blockquote>
<p>📌 
각 프로세스가 CPU를 기다리는지, 입출력을 기다리는지 등의 정보를 커널이 총체적으로 관리</p>
</blockquote>
<ul>
<li><p>작업 큐
: 시스템 내에 모든 프로세스를 관리하기 위한 큐
→ 프로세스의 상태와 무관하게 현재 시스템 내에 있는 모든 프로세스가 작업 큐에 속함
→ 준비 큐와 장치 큐를 오가며 실행되며, 작업 큐가 가장 넓은 개념이다.</p>
</li>
<li><p>장치 큐
  : 운영체제가 어떻게 자료구조로 구현하는지 보여줌</p>
<ul>
<li>큐 헤더 
 : 큐의 가장 앞 부분, 장치 큐에 속한 프로세스들은 봉쇄 상태에 있다가 해당 장치느이 서비스를 받고 나서 장치 컨트롤러가 인터럽트를 발생시키면 준비 상태로 바뀌어 준비 큐로 이동</li>
</ul>
</li>
</ul>
<h2 id="스케줄러">스케줄러</h2>
<p>스케줄러는 어떤 프로세스에게 자원을 할당할지를 결정하는 운영체제 커널의 코드</p>
<ul>
<li>장기 스케줄러(≒ 작업 스케줄러)
: 어떤 프로세스를 준비 큐에 진입시킬지 결정하는 역할
→ 수십 초 내지 수분 단위로 가끔 호출되기 때문에 상대적으로 속도가 느린 것 허용
→ 메모리에 동시에 올라가 있는 프로세스의 수를 조절하는 역할</li>
<li>단기 스케줄러(≒ CPU 스케줄러)
: 준비상태의 프로세스 중에서 어떤 프로세스를 다음번에 실행상태로 만들것이지 결정
: 준비 큐에 있는 여러 프로세스들 중 어떠한 프로세스에게 CPU를 할당할 것인지 결정
→ 밀리초 정도의 시간 단위로 매우 빈번하게 호출되기 때문에 수행 속도가 충분히 빨라야 함</li>
<li>중기 스케줄러
  : 너무 많은 프로세스에게 메모리를 할당해 시스템의 성능이 저하되는 경우 이를 해결하기 위해 메모리에 적재된 프로세스의 수를 동적으로 조절하기 위해 추가된 스케줄러<ul>
<li>스왑 아웃
: 메모리에 올라와 있는 프로세스 중 일부를 선정해 이들로부터 메모리를 통째로 빼앗아 그 내용을 디스크의 스왑 영역에 저장</li>
<li>중지 상태 추가</li>
</ul>
</li>
</ul>
<h2 id="프로세스의-생성">프로세스의 생성</h2>
<ul>
<li>부모 프로세스
: 시스템이 부팅된 후 최초의 프로세스는 운영체제가 직접 생산하지만 이미 존재하는 프로세스가 다른 프로세스를 복제 생성한다.
→ 후손 프로세스들을 연쇄적으로 종료시킨 후에야 본인이 종료됨</li>
<li>자식 프로세스
: 부모 프로세스가 자식 프로세스를 생성</li>
</ul>
<h4 id="자원을-획득하는-방법">자원을 획득하는 방법</h4>
<p>생성된 프로세스가 작업을 수행하기 위해서는 자원이 필요하다.
자원을 획득하는 방법은 운영체제 및 자원의 종류에 따라 상이하다.</p>
<ul>
<li>운영체제로부터 직접 자원 할당</li>
<li>부모 프로세스와 자원을 공유해서 사용<ul>
<li>자식과 부모가 같이 CPU를 획득하기 위해 경쟁하는 관계</li>
</ul>
</li>
<li>부모와 자식이 공존하며 수행되는 모델</li>
<li>자식이 종료될 때 까지 부모가 기다리는 모델</li>
</ul>
<p>프로세스가 생성되면 자신만의 독자적인 주소 공간을 갖게 된다.처음 주소공간을 생성할 때 부모 프로세스의 주소 공간 내용을 그대로 복사해 생성한다.</p>
<h4 id="유닉스-시스템의-프로세스-계층도">유닉스 시스템의 프로세스 계층도</h4>
<ol>
<li>프로세스가 마지막 명령을 수행한 후 운영체제에 이를 알려 이루어지는 자발적 종료</li>
<li>비자발적 종료로 부모 프로세스가 자식 프로세스의 수행을 강제로 종료시키는 것
→ abort() 함수 사용</li>
</ol>
<h4 id="프로세스가-자식-프로세스를-생성하는-법">프로세스가 자식 프로세스를 생성하는 법</h4>
<ol>
<li>fork() 시스템 콜을 제공</li>
<li>프로세스가 fork() 시스템 콜을 하면 CPU의 제어권이 커널로 넘어감</li>
<li>커널은 fork()를 호출한 프로세스를 복제해 자식 프로세스를 생성
→ 부모의 프로세스의 주소공간, 프로그램 카운터, 레지스터 상태, PCB, 커널 스택 등 모든 문맥을 그대로 복제<blockquote>
<p>📌
부모 프로세스의 처음부터 수행하는 것이 아닌 부모 프로세스가 현재 수행한 시점부터 수행하게 된다는 것</p>
</blockquote>
</li>
</ol>
<p>복제된 프로세스는 자기사 복제본이 아니라 원본이며, 자기를 복제해서 복제본이 생성됐다는 기억을 갖는다.
복제본이라는 단서는 fork() 함수의 결과값을 원본에는 양수로 주고 복제본에는 0을 준다.</p>
<h2 id="프로세스-간의-협력">프로세스 간의 협력</h2>
<p>프로세스가 다른 프로세스의 주소 공간을 참조하는 것은 허용되지 않는다.
원칙적으로 다른 프로세스의 수생에 영향을 미칠 수 없는 독립적인 관계가 된다.
경우에 따라 협력을 통해 효율성을 증진시키는데 협력을 위한 메커니즘으로 <strong>IPC(Inter-Process Communication)</strong>가 있다.</p>
<ul>
<li>IPC(Inter-Process Communication)
: 하나의 컴퓨터 안에 실행 중인 서로 다른 프로세스 간에 발생하는 통신이며 동기화를 보장해준다.<ul>
<li>메시지 전달(Message passing)
: 프로세스 간에 공유 데이터를 일체 사용하지 않고 메세지를 주고받으면서 통신하는 방법이며 send, receive 연산으로 제공받는다.<ul>
<li>직접 통신
: 통신하려는 프로세스이 이름을 명시적으로 표시</li>
<li>간접 통신
: 메세지를 메일박스 또는 포트로부터 전달 받는다.
→ 두 방식의 차이는 연산의 인터페이스에 대한 차이일 뿐 실제 메세지 전송이 이뤄지는 내부 구현은 커널의 중재에 의해 사실상 동일한 방식으로 이뤄진다.</li>
</ul>
</li>
<li>공유 메모리(Shared Memory)
: 주소 공간의 일부를 공유하며 프로세스들끼리 직접 공유메모리 접근에 대한 동기홤 문제를 책임져야한다</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS 기초] 네트워크]]></title>
            <link>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-iigb8qpf</link>
            <guid>https://velog.io/@sohyeonbak_oly/CS-%EA%B8%B0%EC%B4%88-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-iigb8qpf</guid>
            <pubDate>Sat, 25 Jun 2022 01:53:50 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>&#39;성공과 실패를 결정하는 1%의 네트워크 원리&#39; 책을 바탕으로 정리한 내용입니다.</p>
</blockquote>
<h1 id="03-데이터를-송·수신한다">03. 데이터를 송·수신한다</h1>
<h2 id="프로토콜-스택에-http-리퀘스트-메시지를-넘긴다">프로토콜 스택에 HTTP 리퀘스트 메시지를 넘긴다</h2>
<p>connect에서 애플리케이션에 제어가 되돌아오면 데이터 송·수신 동작이 되고 애플리케이션이 write를 호출해 송신데이터를 프로토콜 스택에 건네주고 이것을 받은 프로토콜 스택이 송신 동작을 실행한다.</p>
<ul>
<li>프로토콜 스택은 데이터 내용을 알지 못함</li>
<li>데이터 길이 만큼만 바이너리 데이터가 1바이트씩 차례로 나열되고 있다고만 인식</li>
</ul>
<h4 id="🏷-프로토콜-스택의-송신-동작">🏷 프로토콜 스택의 송신 동작</h4>
<ul>
<li><p>받은 데이터를 바로 송신하는 것이 아니라 버퍼 메모리 영역에 저장 후 애플리케이션에서 다음 데이터를 건네주기를 기다림
  → 기다리는 이유는 한꺼번에 송신 의뢰하는 경우도 있고, 1바이트나 1행씩 건네주는 방법도 있어서 프로토콜 스택에서 길이를 제어할 수 없다.
  → <strong>데이터 길이를 알지도 못한채 받아온 데이터를 바로 보내주면 네트워크 이용 효율에 문제가 생김</strong></p>
</li>
<li><p>송신 동작의 판단 요소</p>
<ul>
<li><p>한 패킷에 저장할 수 있는 데이터 크기 </p>
<blockquote>
<ul>
<li>MTU 매개 변수 
: 한 패킷으로 운반할 수 있는 디지털 데이터의 최대 길이,
이더넷에서는 1,500바이트</li>
<li>MSS
: 패킷의 헤더를 제외하고 하나의 패킷으로 운반할 수 있는 데이터의 최대 길이,
MSS를 초과하거나 MSS에 가까운 길이에 이르기 까지 데이터를 저장하고 송신동작을 하면 패킷을 잘게 나눌 걱정할 필요 없다.</li>
</ul>
</blockquote>
</li>
<li><p>타이밍
: 송신 속도가 느려지는 경우 버퍼에 데이터가 모이지 않아도 적당한 곳에서 송신 동작 실행,
프로토콜 스택의 내부 타이머로 일정 시간 이상 경과 하면 패킷을 송신</p>
</li>
</ul>
</li>
</ul>
<p>→ 전자를 중시할 경우 패킷 길이가 길어져 네트워크 이용 효율 높아지지만 버퍼에 머무는 시간 만큼 송신 동작이 지연 될 수 있음.
→ 후자를 중시할 경우 지연은 적어지지만 이용 효율이 떨어질 수 있음</p>
<h2 id="데이터가-클-때는-분활하여-보낸다">데이터가 클 때는 분활하여 보낸다</h2>
<p>HTTP 리퀘스트 메세지 중 한 개의 패킷을 넘어가는 긴 메세지 일 경우 </p>
<ol>
<li>송신 버퍼에 들어있는 데이터를 맨 앞부터 차례대로 MSS의 크기에 맞게 분할</li>
<li>분할된 조각을 한개씩 패킷에 넣어 송신한다.<ul>
<li>패킷 맨 앞에는 TCP 헤더를 부가하고 송/수신처 포트번호 등 중요한 항목을 기록</li>
</ul>
</li>
<li>IP 담당 부분에 건네주어 송신 동작을 실행한다.</li>
</ol>
<h2 id="ack-번호를-사용하여-패킷이-도착했는지-확인한다">ACK 번호를 사용하여 패킷이 도착했는지 확인한다.</h2>
<p>TCP에는 송신한 패킷이 상대에게 올바르게 도착했는지 확인하는 동작으로 넘어간다.</p>
<h4 id="🏷-확인-방법에-대한-개념">🏷 확인 방법에 대한 개념</h4>
<ul>
<li>데이터를 조각으로 분할할 때 몇 번째 바이트에 해당하는지 기록</li>
<li>시퀀스 번호
 : 데이터의 조각을 송신할 때 세어둔 값을 TCP 헤더에 기록하는 것 <ul>
<li>패킷 전체의 길이에서 헤더의 길이를 빼면 크기를 계산 할 수 있기 때문에 크기를 따로 수신측에 알리지는 않음</li>
</ul>
</li>
<li>누락이 없는 것을 확인하면 수신측은 그 이전에 수신한 데이터와 함쳐서 데이터를 몇 번째 바이트까지 수신한 것인지 계산</li>
<li>그 값은 TCP 헤어의 <strong>ACK 번호</strong>에 기록</li>
<li><em>→ 수신응답 확인 과정*</em></li>
</ul>
<blockquote>
<p>📌 
시퀀스 번호는 1부터 시작하지 않고 난수로 시작해 예측할 수 없게 만듦.
그러나 난수로 지정하게 되면 초기값을 알 수 없는 문제가 생김으로 접속 동작 부분에서 SYN이라는 제어비트를 1로 하여 초기값을 통지한다.
→ SYN에 1를 설정할 때 시퀀스 번호에도 값을 설정하게 되어 <strong>시퀀스 번호의 값이 초기값을 나타낸다.</strong></p>
</blockquote>
<blockquote>
<p>📌
TCP의 데이터 송·수신 동작은 양방향이므로 클라이언트에서 서버로 향하는 데이터 흐름과 서버에서 클라이언트로 향하는 두가지 데이터 흐름이 있어서 각각 대응해줘야한다.</p>
</blockquote>
<h4 id="🏷-클라이언트→서버">🏷 클라이언트→서버</h4>
<ul>
<li>시퀀스 번호는 클라이언트 측에서 산출하여 데이터와 함께 서버에 통지</li>
<li>서버측에서 ACK 번호를 산출 후 클라이언트에 반송</li>
</ul>
<h4 id="🏷-서버→클라이언트">🏷 서버→클라이언트</h4>
<ul>
<li>데이터에 관한 시퀀스 번호는 서버에서 산출해 데이터와 함께 클라이언트에 통지</li>
<li>클라이언트 측에서 ACK 번호를 산출해 서버에 응답</li>
</ul>
<p>→TCP는 이 방법으로 확인 할 때 까지 송신한 패킷을 송신용 버퍼 메모리에 보관하고 대응하는 ACK 번호가 상대로부터 돌아오지 않으면 다시 패킷을 보낸다.</p>
<ul>
<li>오류가 발생해도 전부 검출해 회복처리를 취할 수 있고</li>
<li>다른 곳에서 오류를 위한 회복 조치를 할 필요 없다.</li>
</ul>
<h2 id="패킷-평균-왕복-시간으로-ack-번호의-대기-시간을-조정">패킷 평균 왕복 시간으로 ACK 번호의 대기 시간을 조정</h2>
<p>타임아웃 값
: ACK 번호가 돌아오는 것을 기다리는 시간</p>
<ul>
<li>대기 시간을 적정하게 두지 않으면 ACK 번호의 반송이 지연됨으로 혼잡해진다.</li>
<li>대기시간을 무조건 길게 하면 패킷을 다시 보내는 동작이 지연되어 속도 저하가 생길 수 있다
→ TCP는 대기시간을 동적으로 변경하는 방법을 취한다</li>
</ul>
<h2 id="윈도우-제어-방식으로-효율적으로-ack-번호를-관리한다">윈도우 제어 방식으로 효율적으로 ACK 번호를 관리한다</h2>
<p>윈도우 제어
: 한 개의 패킷을 보낸 후 ACK 번호를 기다리지 않고 차례대로 연속해서 복수의 패킷을 보내는 방법</p>
<ul>
<li><p>핑퐁 방식
: ACK 번호를 기다리지 않고 차례로 패킷을 보내면 수신측의 능력을 초과해 패킷을 보내는 사태가 생길 수 있음
데이터 속도가 애플리 케이션에서 건네주는 속도보다 빠르면 수신 버퍼에 데이터가 넘처흘리게 되는 것을 <strong>수신측의 능력을 초과한다는 의미</strong></p>
</li>
<li><p>윈도우 필드
: 수신 처리가 끝나고 수신 버페어 빈 부분이 생기면 그 분량만큼 수신할 수 있는 데이터 양을 늘려서 TCP 헤더의 윈도우 필드에서 송신측에 알린다.</p>
</li>
<li><p>윈도우 사이즈
: 수신가능한 데이터 양의 최대값</p>
</li>
</ul>
<h2 id="ack-번호와-윈도우를-합승한다">ACK 번호와 윈도우를 합승한다</h2>
<h4 id="🏷-윈도우-통지와-ack-번호">🏷 윈도우 통지와 ACK 번호</h4>
<ol>
<li>송신측에서 보낸 데이터가 수신측에 도착해 정상완료</li>
<li>ACK 번호를 송신측에 통지 후 데이터를 애플리케이션에 건네주고 윈도우를 송신측에 동지하는 상태</li>
<li>수신측은 잠시 기다리는데 그 사이 다음 통지 동작이 일어나면 양쪽을 상승시켜 한개의 패킷으로 묶어서 보냄</li>
<li>ACK 번호와 윈도우를 한개의 패킷에 합승시켜 통지해 패킷의 수를 줄일 수 있다.</li>
</ol>
<h2 id="http-응답-메시지를-수신한다">HTTP 응답 메시지를 수신한다</h2>
<p>브라우저는 리퀘스트 메시지를 송신해 달라고 의뢰하고, 응답 메세지를 받기 위해 read 프로그램을 호출한다.
read를 경유해 프로토콜 스택에 제어가 넘어가고, 프로토콜 스택이 움직인다.
데이터를 임시 보관하는 수신 버퍼를 사용한다.</p>
<ul>
<li>프로토콜 스택
: 수신 버퍼에서 수신 데이터를 추출해 애플리케이션에 건네준다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React의 SSR과 CSR]]></title>
            <link>https://velog.io/@sohyeonbak_oly/React%EC%9D%98-SSR%EA%B3%BC-CSR</link>
            <guid>https://velog.io/@sohyeonbak_oly/React%EC%9D%98-SSR%EA%B3%BC-CSR</guid>
            <pubDate>Sun, 19 Jun 2022 15:16:04 GMT</pubDate>
            <description><![CDATA[<h1 id="react는-spasingle-page-application-이다">React는 SPA(Single Page Application) 이다.</h1>
<p>예전에는 웹 어플리케이션을 개발 할 때 하나의 웹 어플리케이션 안에 해당하는 페이지가 각각 html문서로 하나씩 저장되어있었다.
서버 안에 해당하는 주소의 웹 페이지가 저장되어 있었고, 하나의 웹 어플리케이션에서 화면을 전환 할 때 해당하는 페이지가 서버에서 랜더링해 하나씩 화면에 보여줬었다.
규모가 커지고 인터렉션이 다양해지면서 서버에 하나씩 페이지가 저장되어 있는것은 부담이 되었고 속도 측면에서도 어려움이 생겼다.</p>
<blockquote>
<p><strong>SPA(Single Page Application)</strong>는 하나의 페이지를 다운받아서 화면을 전환하기 위해 새로운 html문서를 다운받아오는 것이 아닌 해당하는 데이터를 요청해 자바스크립트로 콘텐츠만 랜더링해 화면을 전환해주는 것이다.
페이지는 하나이지만 화면 전환이 필요한 부분만 콘텐츠로 받아와 화면에 새로 그려주기 때문에 서버의 과부화를 줄여줄 수 있다.</p>
</blockquote>
<h1 id="csrclient-server-rendering">CSR(Client Server Rendering)</h1>
<p><img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/fc783b6e-1d77-4bb8-a6c5-ed08338d4594/image.png" alt=""></p>
<p>React의 SPA를 설명하기 위해 먼저 CSR을 설명해야 한다.
말 그대로 서버가 아닌 클라이언트에서 랜더링 처리를 하는 것이다.</p>
<ol>
<li>브라우저에서 해당 웹 어플리케이션을 요청하면 서버는 브라우저에게 해당 HTML문서를 브라우저에게 응답한다.</li>
<li>브라우저는 해당 HTML문서를 받아 JavaScrip 파일을 다운로드한다.</li>
<li>브라우저는 React를 실행시킨다.</li>
<li>화면에서 브라우저와 인터렉션을 함께 보여준다.</li>
</ol>
<h1 id="ssrserver-side-rendering">SSR(Server Side Rendering)</h1>
<p><img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/871a8247-c58d-48e5-bf44-d346f6e432e1/image.png" alt=""></p>
<p>React에서의 SSR은 이런 방식으로 진행된다.</p>
<ol>
<li>브라우저에서 요청한 웹 어플리케이션을 서버에서는 랜더링한 HTML 문서를 준비하고 브라우저로 응답한다.</li>
<li>브라우저는 랜더링된 페이지를 바로 보여주고 JavaScript 파일을 다운로드 한다.</li>
<li>다운로드가 끝나면 브라우저에서 React를 실행한다.</li>
<li>화면에서 인터렉션을 할 수 있게 된다.</li>
</ol>
<h1 id="ssr-vs-csr">SSR vs CSR</h1>
<p>두 개의 주요 차이점은 SSR은 서버의 응답으로 보내준 HTML문서가 이미 랜더링 되어서 보내지는 것이고, CSR은 자바스크립트 소스가 포함된 빈 HTML문서를 보내준다는 것이다.
브라우저는 자바스크립트가 서버에서 다운로드되고 실행되는 것을 기다리지 않고 HTML 문서를 랜더링을 시작한다.
두 방식 모두 JavaScript를 다운로드 하고 Virtual DOM을 구축한 다음 페이지를 인터렉티브하게 만들기 위해 event binding을하는 방식을 거친다.
그러나 SSR은 JavaScript를 다운받는 동안 서버에서 미리 그려진 HTML 파일을 볼 수 있지만 CSR은 JavaScript를 다운로드 받고 실행해 Virtual DOM을 브라우저의 실제 DOM으로 그린 후 보여질 수 있다. </p>
<h1 id="ssr의-몇가지-문제">SSR의 몇가지 문제</h1>
<ul>
<li>페이지가 미리 랜더링 되서 브라우저에 응답받기 때문에 화면에 빠르게 페이지를 볼 수 있지만 JavaScript 파일이 실행이 되지 않기 때문에 event binding이 제대로 되지 않아 인터렉티브가 제대로 동작하지 않을 수 있다.</li>
<li>SSR TTFB(Time To First Byte)가 CSR에 비해서 느리다. CSR은 빈 페이지를 응답하면 되지만 SSR은 페이지를 랜더링 후 보내야 하기 때문에 응답시간이 느릴 수 밖에 없다.</li>
<li>CSR의 출력량이 SSR보다 훨씬 많다.<pre><code class="language-javascript">ReactDOMServer.renderToString</code></pre>
</li>
</ul>
<p>ReactDOMServer.renderToString은 동기적으로 CPU에 요청을 하고 그것은 event loop을 발생하게 되어 서버에서 ReactDOMServer.renderToString가 끝나지 않으면 다른 어떤 요청도 불가능해진다. 
SSR에서 페이지를 1개 랜더링하는데 500ms가 걸리면 그동안 아무것도 진행 할 수 없게 된다.</p>
<p><img src="https://velog.velcdn.com/images/sohyeonbak_oly/post/db3293ac-e292-4ae1-8078-a154bd249fb1/image.png" alt=""></p>
<p>📌이 외에도 SSR을 사용하면 SEO문제를 해결해 줄 수 있고, 고객을 위한 성능 이점이 있다는 장점 또한 가지고 있다.
React의 랜더링 방식에 대해 어떤 것을 사용할지 정하는 일은 어떤 웹 어플리케이션을 제작하고 그것에 가장 중요한 이슈를 해결해주는 방식을 채택하는 것이 중요할 것 같다.</p>
<h3 id="참고자료">참고자료</h3>
<p><a href="https://medium.com/walmartglobaltech/the-benefits-of-server-side-rendering-over-client-side-rendering-5d07ff2cefe8">https://medium.com/walmartglobaltech/the-benefits-of-server-side-rendering-over-client-side-rendering-5d07ff2cefe8</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[클라우드]Cloud Computing]]></title>
            <link>https://velog.io/@sohyeonbak_oly/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9CCloud-Computing</link>
            <guid>https://velog.io/@sohyeonbak_oly/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9CCloud-Computing</guid>
            <pubDate>Thu, 16 Jun 2022 23:49:14 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>&#39;그림으로 배우는 클라우드 Cloud computing&#39; 책을 기반으로 작성한 블로그 입니다.</p>
</blockquote>
<h1 id="클라우드란">클라우드란</h1>
<h2 id="클라우드-컴퓨팅">클라우드 컴퓨팅</h2>
<p>: 컴퓨터를 사용한 정보 처리를 자신이 보유한 pc가 아닌 인터넷 너머에 존재하는 클라우드에 처리하는 서비스</p>
<ul>
<li>사고방식 혹은 개념을 나타내는 단어</li>
<li>NIST가 정한 정의 : 공유 구성이 가능한 컴퓨팅 리소스의 통합으로 요청에 따라 네트워크를 통해 접근하는 모델, 효율적인 상호작용으로 신속하게 제공됨<ul>
<li>주문형 셀프 서비스</li>
<li>광범위한 네트워크 접속</li>
<li>리소스의 공유</li>
<li>신속한 확장성</li>
<li>측정 가능한 서비스</li>
</ul>
</li>
</ul>
<p>1980: 메인프레임(대형 범용 컴퓨터) - 데이터와 어플리케이션을 모두 메인 프레임에 저장, 단말기는 입출력 표시만 담당
1990: 분산형 클라이언트 서버 모델 - 단말기에도 처리 기능 부여
2000: 사내 시스템이 네트워크 환경에 구축되면서 처리가 서버로 집중
2010: 클라우드 컴퓨팅 - 분산 배치된 서버 리소스를 필요할 때 필요한 만큼 사용가능</p>
<ul>
<li>기술 발전 : CPU 처리 속도 고속화</li>
<li>가상화 기술과 분산 처리 기술 발전</li>
<li>모바일의 융성과 빨라지고 저렴해진 네트워크</li>
<li>거대해진 데이터 센터 </li>
</ul>
<h2 id="saassoftware-as-a-service">SaaS(Software as a Service)</h2>
<p>: 주로 업무에서 사용하는 소프트웨어의 기능을 네트워크를 통해 필요한 만큼 서비스로 이용할 수 있도록 제공</p>
<ul>
<li>하나의 서버를 여러 기업에서 공유하는 것을 전제한 멀티 테넌트 방식</li>
<li>전자메일, 그룹웨어, CRM</li>
</ul>
<h2 id="paasplatform-as-a-service">PaaS(Platform as a Service)</h2>
<p>: 기업의 애플리케이션 실행 환경 및 애플리케이션 개발 환경을 서비스로써 제공하는 모델, 애플리케이션 실행 환경이나 데이터베이스 등이 미리 마련</p>
<ul>
<li>SaaS와의 차이점 : 서버, 네트워크, 보안 부분을 클라우드 사업자에게 위임, SaaS는 정해진 소프트웨어를 서비스로 제공/PaaS는 자사에서 개발한 응용 프로그램 가동<ul>
<li>활용자유도가 높지만 서버 및 미들웨어의 상세 설정을 할 수 없고</li>
<li>PaaS 의존도가 높으면 다른 환경으로 마이그레이션이 어려워짐</li>
</ul>
</li>
<li>스마트폰이나 테블릿 등 모바일 서비스에서 인터넷 접속, IoT 등</li>
</ul>
<h2 id="iaasinfrastructure-as-a-service">IaaS(Infrastructure as a Service)</h2>
<p>: CPU나 하드웨어 등 컴퓨팅 리소스를 네트워크를 통해 서비스로 제공하는 모델</p>
<ul>
<li>가상 서버 및 온라인 스토리지 <ul>
<li>가상 서버 :  클라우드 사업자가 보유한 물리적 서버의 CPU나 메모리, 스토리지 등의 하드웨어 자원을 소프트웨어적으로 나누어 사용자에게 제공<ul>
<li>필요할때 필요한 만큼만 가상 서버를 만들어 사용</li>
<li>OS에 설치되는 데이터베이스와 미들웨어, 응용 프로그램 등의 소프트웨어를 자유롭게 운영하고 스스로 관리하고 설치</li>
</ul>
</li>
</ul>
</li>
<li>웹 사이트 서버용, 기업의 ERP</li>
</ul>
<h2 id="클라우드-이용-모델">클라우드 이용 모델</h2>
<ul>
<li>퍼블릭 클라우드
  : 클라우드 사업자가 시스템을 구축하고, 인터넷망 등의 네트워크를 통해 불특정 다수의 기업과 개인에게 서비스를 제공하는 형태</li>
<li>프라이빗 클라우드
  : 클라우드 서비스의 사용자 또는 사업자의 데이터 센터에 클라우드 관련 기술이 활용된 자사 전용 환경을 구축해 컴퓨팅 리소스를 유연하게 이용하는 형태<ul>
<li>종류<ul>
<li>온프레미스 프라이빗 클라우드
  : 기업 사용자가 스스로 클라우드 기반 소프트웨어를 이용하고 자체적으로 구입한 서버 및 스토리지, 하드웨어 리소스 기업 안에 설치해 자사 전용 클라우드 환경을 구축해서 운영하는 형태
  : 자체적인 보안 정책에 따른 강력한 보안 환경을 구축해서 운용</li>
<li>호스티드 프라이빗 클라우드
  : 클아우드 사업자가 기업 사용자 별로 클라우드 환경 제공</li>
</ul>
</li>
</ul>
</li>
<li>커뮤니티 클라우드
  : 공통의 목적을 가진 특정 기업들이 클라우드 시스템을 형성하여 데이터 센터에서 공동 운영하는 형태</li>
<li>하이브리드 클라우드
  : 퍼블릭 클라우드, 프라이빗 클라우드, 커뮤니티 클라우드 같은 서비스들과 온프레미스 시스템을 연계 시켜 활용</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>