<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Android</title>
        <link>https://velog.io/</link>
        <description>developer</description>
        <lastBuildDate>Tue, 15 Jun 2021 15:01:50 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. Android. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jaeyunn_15" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Android] Layout을 파헤치자 🧤]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-ConstraintLayout-RelativeLayout-LinearLayout</link>
            <guid>https://velog.io/@jaeyunn_15/Android-ConstraintLayout-RelativeLayout-LinearLayout</guid>
            <pubDate>Tue, 15 Jun 2021 15:01:50 GMT</pubDate>
            <description><![CDATA[<h3 id="layout">Layout</h3>
<ul>
<li>View 위젯들을 그룹화하여 배치하기 위한 용도로 사용되는 ViewGroup</li>
</ul>
<h3 id="viewgroup">ViewGroup</h3>
<ul>
<li>다른 View를 포함할 수 있는 View</li>
<li>컨테이너 역할을 수행</li>
</ul>
<hr>
<h3 id="linearlayout--relativelayout--framelayout">LinearLayout &amp; RelativeLayout &amp; FrameLayout</h3>
<h4 id="linearlayout">LinearLayout</h4>
<ul>
<li><strong>여러 View 위젯들을 가로/세로 방향으로 나열할 때 사용하는 Layout</strong></li>
<li>orientation 속성을 가지고 있어 가로(Horizontal), 세로(Vertical)을 설정할 수 있다.</li>
<li>자식들은 중첩되지 않고 지정한 방향으로 쌓이는 형태로 표시된다.</li>
<li>weight 속성으로 가중치를 설정할 수 있다. 비율로 나타낼 수 있다. 
다양한 디바이스 화면에 dp가 아니라 비율에 따른 대응으론 좋다. (그러나 onLayout()를 자주 호출하여 상관관계를 파악하기에 성능상 좋진 않다)</li>
</ul>
<h4 id="relativelayout">RelativeLayout</h4>
<ul>
<li><strong>자식 View 위젯들이 서로 간의 상대적 배치 관계에 따라 화면에 표시될 위치가 결정되도록 만들어주는 Layout 클래스</strong></li>
<li><strong><em>상대적인</em></strong> 배치 기준을 정하지 않는다면, 내부에서 중첩되어 표시된다.</li>
<li>특정 위젯을 기준으로 배치하게 된다. </li>
<li>아무런 조작을 하지 않았을 때는 왼쪽 상단부터 위젯이 쌓이게 된다.</li>
</ul>
<h4 id="framelayout">FrameLayout</h4>
<ul>
<li><strong>주로 하나의 자식 View위젯만 표시할 때 사용하는 layout 클래스.</strong></li>
<li>추가된 순서대로 쌓이게 되기에 마지막에 추가된 뷰가 가장 위에 올라오게 된다.</li>
<li>여러 Fragment를 동일한 위치 내에서 교체하여 표시하고자 할 때, Fragment의 컨테이너 역할로써 FrameLayout을 주로 사용한다.</li>
<li>보통 로딩중 Progress를 보여줄 때</li>
</ul>
<hr>
<h3 id="constraintlayout">ConstraintLayout</h3>
<blockquote>
<p>레이아웃에 배치되는 뷰들에 여러 제약을 적용하여 각 뷰의 위치와 크기를 결정하는 레이아웃</p>
</blockquote>
<ul>
<li><p>RelativeLayout의 <strong>상대적 위치 관계에 따른 배치</strong> + LinearLayout의 <strong>가중치가 가진 장점</strong> + chain 사용을 다른 레이아웃 없이 <strong>요소들을 그룹화</strong></p>
</li>
<li><p>ConstraintLayout는 <strong>성능향상</strong>을 얻을 수 있다. (수평적인 구조로 인해)</p>
</li>
<li><p>ConstraintLayout은 레이아웃에 배치되는 뷰들에 여러 제약을 적용하여 각 뷰의 위치와 크기를 결정한다.</p>
</li>
</ul>
<h3 id="relativelayout-1">RelativeLayout</h3>
<blockquote>
<p>레이아웃 내의 자식 뷰 위젯들이 서로 간의 상대적 위치 관계에 따라 최종적으로 표시될 영역을 결정하도록 만드는 레이아웃</p>
</blockquote>
<hr>
<h3 id="왜-constraintlayout을-써야할까">왜 ConstraintLayout을 써야할까?</h3>
<p>LinearLayout, RelativeLayout, ConstraintLayout의 효율을 비교한 포스팅이 있어서 가져왔다.</p>
<blockquote>
<p><a href="https://beenii.tistory.com/72">이 글</a>에서는 ConstraintLayout을 LinearLayout, RelativeLayout 대비해서 설명하고 있다.</p>
</blockquote>
<p>해당 글에선 onMeasure() 호출 개수를 가지고서 레이아웃 성능 비교를 하고 있다.
<img src="https://images.velog.io/images/jaeyunn_15/post/bcc1423e-b591-451b-a0a1-f58f131c1a2e/image.png" alt="">
<img src="https://images.velog.io/images/jaeyunn_15/post/18a40f93-807a-434d-9650-58534819b048/image.png" alt="">
<img src="https://images.velog.io/images/jaeyunn_15/post/a206d9f6-e41d-4819-a467-03a7e49b03da/image.png" alt=""></p>
<p>이렇게 3가지의 비교만 보더라도 ConstraintLayout의 호출횟수가 적은 것을 볼수 있다.
onMeasure() 메서드는 뷰의 크기를 구하는 역할을 하게 되는데 이 과정을 
LinearLayout은 10번
RelativeLayout은 14번
ConstraintLayout은 8번을 수행한다.</p>
<p>특히, RelativeLayout의 경우, 특정 뷰를 기준으로 상대적인 위치를 나타내기에 특정 뷰 위치를 구하는 것을 반복하게 된다.</p>
<blockquote>
<p>relative layout에서 4 depth이상 들어가야하는 것도 ConstraintLayout에선 1 depth로 가능!!!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] View가 렌더링되는 과정 📱]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-View%EA%B0%80-%EB%A0%8C%EB%8D%94%EB%A7%81%EB%90%98%EB%8A%94-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@jaeyunn_15/Android-View%EA%B0%80-%EB%A0%8C%EB%8D%94%EB%A7%81%EB%90%98%EB%8A%94-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Tue, 15 Jun 2021 10:51:58 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>위 글의 대부분의 내용은 <a href="https://www.charlezz.com/?p=34935">안드로이드 View가 렌더링 되는 과정</a> 해당 글을 참고하여 적었습니다. </p>
</blockquote>
<h3 id="intro">Intro</h3>
<p>안드로이드의 화면은 아래와 같은 단위로 구성된다. 화면을 구성하는 최소단위는 View이며 최대 단위는 Window이다.</p>
<p><strong>Window &gt; Surface &gt; Canvas &gt; View</strong></p>
<p><strong>Window</strong></p>
<ul>
<li>화면 구성의 가장 상위 요소로 무언가를 그릴 수 있는 화면 상 사각 영역이다.</li>
<li>어플리케이션에서는 각각의 Window에 Surface를 만들어 어플리케이션에 전달하고, 어플리케이션은 이를 통해 화면을 렌더링한다.</li>
<li>터치 이벤트, 키 이벤트 등 사용자 이벤트를 받아 처리할 수 있다.</li>
<li>statusBar</li>
<li>SoftKey</li>
</ul>
<p><strong>Surface</strong></p>
<ul>
<li>Surface는 화면에 합성되는 픽셀을 보유한 객체</li>
<li>화면에 표시되는 모든 Window(StatusBar, Dialog, Activity etc)는 자신만의 Surface를 가지고 있으며</li>
<li>Surface Flinger가 여러 소스로부터 그래픽 데이터 버퍼를 받고, 그것들을 합성하여 display로 보낸다.</li>
</ul>
<p><strong>Canvas</strong></p>
<ul>
<li>모든 드로인 메서드를 포함하고 있는 클래스</li>
<li>각종 도형, 선 등을 그리기 위한 모든 로직이 Canvas에 포함되어 있다.</li>
<li>Bitmap 또는 OpenGL 컨테이너 위에 그려진다.</li>
</ul>
<h3 id="view-렌더링-과정">View 렌더링 과정</h3>
<p>XML로 작성한 View가 어떻게 최종적으로 화면에 렌더링 되는 지 ?</p>
<p>Android에서는 Activity가 Focus를 얻게 되면 자신의 Layout을 그린다.</p>
<p>이때 그리고자 하는 Layout의 <strong>Root Node</strong>를 요청하게 되는데, 우리가 setContentView()를 호출할 때 Root Node가 정해진다.</p>
<p>Root Node가 결정되면 <strong>Root Node를 따라 Child Node를 따라가면서 차례대로 View를 그리게 된다.</strong></p>
<hr>
<h3 id="그리는-순서">그리는 순서</h3>
<p>Layout을 그리는 건 측정과 순서란 과정을 따른다.</p>
<p><code>measure()</code> &gt; <code>onMeasure()</code> &gt; <code>layout()</code> &gt; <code>onLayout()</code></p>
<ul>
<li><p><strong>measure(widthMeasureSpec :Int, heightMeasureSpec:Int)</strong></p>
<ul>
<li>뷰의 크기를 알아내기 위해 호출되며, 실제 크기 측정을 위해 <code>onMeausre()</code>를 호출한다.</li>
<li>widthMeasureSpec : Parent가 뷰여한 필요한 가로 공간</li>
<li>heightMeasureSpec : Parent가 부여한 필요한 세로 공간</li>
</ul>
</li>
<li><p><strong>onMeasure(widthMeasureSpec :Int, heightMeasureSpec:Int)</strong></p>
<ul>
<li>실제 뷰의 크기를 측정한다.</li>
<li>widthMeasureSpec : Parent가 뷰여한 필요한 가로 공간</li>
<li>heightMeasureSpec : Parent가 부여한 필요한 세로 공간   </li>
</ul>
</li>
<li><p><strong>layout(left:Int, top:Int, right:Int, bottom:Int)</strong></p>
<ul>
<li>뷰의 위치를 할당하기 위해 호출되며, 실제 할당을 위해 <code>onLayout()</code>을 호출한다.</li>
<li>left : Parent에 대한 왼쪽 포지션</li>
<li>top : Parent에 대한 위쪽 포지션</li>
<li>right : Parent에 대한 오른쪽 포지션</li>
<li>bottom : Parent에 대한 하단 포지션    </li>
</ul>
</li>
<li><p>*<em>onLayout(changed:Boolean, left:Int, top:Int, right:Int, bottom:Int) *</em></p>
<ul>
<li>실제 뷰의 크기 및 위치를 할당한다.</li>
<li>changed : 새로운 사이즈나 위치인지 맞으면 True/False</li>
<li>left : Parent에 대한 왼쪽 포지션</li>
<li>top : Parent에 대한 위쪽 포지션</li>
<li>right : Parent에 대한 오른쪽 포지션</li>
<li>bottom : Parent에 대한 하단 포지션       </li>
</ul>
</li>
</ul>
<hr>
<h3 id="view의-생명주기">View의 생명주기</h3>
<p>measure() &gt; layout() &gt; draw()
<img src="https://images.velog.io/images/jaeyunn_15/post/388dcc78-9cea-47de-82c6-f732d2c3d114/image.png" alt=""></p>
<h4 id="onattachtowindow">onAttachToWindow()</h4>
<ul>
<li>뷰가 윈도우에 붙었을때 호출</li>
<li>Parent View가 addView(view:View)를 호출하면 해당 View가 window에 연결된다. 이 단계부터 id를 통해 접근 가능하다.</li>
</ul>
<h4 id="measure">measure()</h4>
<ul>
<li><strong>🌟뷰들의 사이즈를 측정(결정)</strong></li>
</ul>
<h4 id="onmeasure">onMeasure()</h4>
<ul>
<li>View의 사이즈를 측정</li>
<li><strong>요구된 View와 Child View의 사이즈가 결정되면 호출</strong>된다.</li>
</ul>
<h4 id="layout">layout()</h4>
<h4 id="onlayout">onLayout()</h4>
<ul>
<li>Child 뷰의 사이즈 및 위치 할당</li>
<li>View와 ChildView의 사이즈와 포지션을 적용할 때 호출</li>
<li><strong>🌟뷰를 측정하여 화면에 배치한 후 호출</strong>된다.</li>
</ul>
<h4 id="dispatchtodraw">dispatchToDraw()</h4>
<h4 id="ondraw">onDraw()</h4>
<ul>
<li>Canvas와 Paint를 사용해서 뷰를 그리기 시작</li>
<li>뷰가 화면에 컨텐츠(텍스트,이미지 등)을 그릴 준비가 되었을 때 호출</li>
<li><strong>Canvas 객체를 생성하고 뷰를 그린다.</strong></li>
</ul>
<hr>
<h3 id="view-update">View Update</h3>
<ul>
<li>특정 속성이 변경되었을 때 호출되는 메서드</li>
</ul>
<h4 id="invalidate">invalidate()</h4>
<ul>
<li>변경사항을 보여주고자 하는 <strong>특정 뷰에 대해 강제로 다시 그리기를 요구</strong>하는 메소드.</li>
<li>뷰 모양이 변경되면 invalidate()를 호출해야 한다.</li>
</ul>
<h4 id="requestlayout">requestLayout()</h4>
<ul>
<li>어떤 시점에서 <strong>뷰의 경계가 변경되었다면,</strong> View를 다시 측정하기 위해 requestLayout()을 호출하여 Measure 및 Layout 단계를 다시 거칠 수 있다.</li>
</ul>
<hr>
<h3 id="rasterization-래스터화">Rasterization (래스터화)</h3>
<blockquote>
<p>문자열, 버튼 또는 도형과 같은 객체들을 픽셀로 변환시키고 스크린 상의 텍스처로 나타내는 과정을 말한다.</p>
</blockquote>
<ul>
<li>레스터화는 비용이 큰 작업에 속한다.</li>
<li>그러므로 GPU가 래스터화 가속을 위해 사용된다.</li>
<li>CPU는 polygon, texture 등을 계산하고 처리하는 데 특화되어 설계되었다.(병렬 처리)</li>
</ul>
<p>CPU는 화면에 무언가 그리기 위해 GPU에게 폴리곤이나 텍스쳐의 래스터화를 위임하고 GPU의 최종적인 처리 결과가 화면에 나타난다.
<img src="https://images.velog.io/images/jaeyunn_15/post/2d5289ab-da91-47ad-9145-520a3cd3d9e5/image.png" alt=""></p>
<p>이러한 CPU와 GPU의 데이터 전송 처리는 일반적으로 OpenGL ES API의 호출에 의해 일어난다.
안드로이드에서 점,선,면을 포함한 버튼, 이미지 등의 UI 객체가 화면에 나타나기 위해서는 항상 OpenGL ES를 거치게 된다.
OpenGL은 3개의 정점을 이어 하나의 삼격형을 이루고 이를 PolyGon이라고 한다. 
Polygon이 모여 메쉬를 이룬다.
<img src="https://images.velog.io/images/jaeyunn_15/post/a0a5af08-881f-49b0-93b4-5c0dab56d442/image.png" alt="">
예를 들어, 아주 간단한 UI
<strong>버튼을 화면에 렌더링 하는 과정</strong>을 생각해보자.
우선, 버튼이 있어야 하고, 이를 CPU에 의해 폴리곤과 텍스처로 변환 시킨 뒤 GPU에게 넘겨지게 된다.</p>
<p>UI객체를 메쉬로 변환하는 과정은 비용이 큰 작업이다. 
모든 변환 과정이 끝난 뒤 변환된 데이터가 OpenGL ES API에 의해 CPU에서 GPU로 전달되게 된다.</p>
<p>결국 <strong>렌더링 퍼포먼스를 최적화한다는 의미</strong>는 _GPU메모리에 데이터를 얼마나 많이 적재하고 제거하며 이를 얼마나 잘 참조하냐_이다.</p>
<hr>
<h3 id="ui-퍼포먼스">UI 퍼포먼스</h3>
<h4 id="overdraw--ui-퍼포먼스를-저하">OverDraw &gt; UI 퍼포먼스를 저하</h4>
<p>오버드로우는 시스템이 단일 렌더링 프레임에서 같은 픽셀을 여러번 덧 그리는 것이다.
이러한 GPU의 리소스 낭비로 인해 퍼포먼스가 떨어지고, 사용자에게 나쁜경험을 제공할 수 있다.</p>
<h4 id="오버드로잉을-줄이기-위한-몇가지-방법">오버드로잉을 줄이기 위한 몇가지 방법</h4>
<ul>
<li>레이아웃에서 불필요한 배경 제거</li>
<li>뷰 계층을 평탄화 하기<ul>
<li>이때 ConstraintLayout의 큰 효과를 볼 수 있다.</li>
<li>ConstraintLayout은 레이아웃 내에 또 다른 레이아웃을 포함시킬 필요 없이 간단한 제약조건으로 평탄한 계층 구조를 만든다.</li>
<li>평탄한 뷰 계층을 구성하여 퍼포먼스를 향상하자.</li>
</ul>
</li>
<li>투명도 줄이기</li>
</ul>
<h3 id="ref">Ref</h3>
<ul>
<li><a href="https://www.charlezz.com/?p=34935">https://www.charlezz.com/?p=34935</a></li>
<li><a href="https://developer.android.com/topic/performance/rendering?hl=ko">https://developer.android.com/topic/performance/rendering?hl=ko</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Runtime & Compiletime ⌛️]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-Runtime-Compiletime</link>
            <guid>https://velog.io/@jaeyunn_15/Android-Runtime-Compiletime</guid>
            <pubDate>Mon, 14 Jun 2021 08:46:54 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>우선 두 용어는 모두 SW 프로그램 개발의 서로 다른 두 계층의 차이를 설명하기 위한 용어이다.</p>
</blockquote>
<h3 id="compiletime-컴파일-타임">Compiletime 컴파일 타임</h3>
<p>프로그램을 생성하기 위해 개발자는 첫째로 <strong>소스코드를 작성하고 컴파일이라는 과정을 통해 기계어 코드로 변환되어 실행 가능한 프로그램</strong>이 된다.</p>
<h3 id="runtime-런타임">Runtime 런타임</h3>
<p>컴파일 과정을 마친 프로그램은 <strong>사용자에 의해 실행되며 이러한 응용프로그램이 동작되어지는 때</strong>를 런타임이라고 한다.</p>
<p>종종 2가지 타입의 에러를 나타내기 위해 사용되어지곤 한다.</p>
<h3 id="오류의-유형-차이">오류의 유형 차이</h3>
<ul>
<li><p>컴파일 타임 오류 유형</p>
<ul>
<li>Syntax 오류</li>
<li>Type check 오류</li>
</ul>
</li>
<li><p>런타임 오류의 유형</p>
<ul>
<li>0 나누기 오류</li>
<li>Null 참조 오류</li>
<li>메모리 부족 오류</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] MultiDex ?]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-MultiDex</link>
            <guid>https://velog.io/@jaeyunn_15/Android-MultiDex</guid>
            <pubDate>Mon, 14 Jun 2021 06:24:41 GMT</pubDate>
            <description><![CDATA[<p>Android는 JVM 기반의 ART 위에서 동작한다.</p>
<h3 id="multidex">MultiDex?</h3>
<p>ART 위에서 동작하기 위해 안드로이드 코드는 dex 파일로 컴파일 된다.
이때, 메서드 수가 64k(65535)개를 초과할 수 없어서 나오게 된 개념이 Multidex이다.</p>
<p>Multidex는 메서드가 64k(65536)개를 초과하지 않도록 dex파일을 여러개로 쪼개주고 쪼개진 dex를 읽을 수 있게 해준다.</p>
<h3 id="어떻게">어떻게?</h3>
<p>minSdkVersion이 21 이상인 경우, multidex는 기본 사용 설정이 된다.</p>
<p>20이하의 경우엔 명시적으로 선언을 해줘야한다.</p>
<pre><code>  // build.gradle

  android{
    complieSdkVersion 28
    defaultConfig{
      ...

      // 멀티덱스 기능 true
      multiDexEnabled true
    }
    ...
  }

  dependencies{
    // 의존성 추가
    implementation &#39;com.android.support:multidex:1.0.3&#39;
  }
  import android.support.multidex.MultiDexApplication;

  public class App extends MultiDexApplication{ // 매니페스트의 앱 이름과 같은 클래스가 상속받아야한다.
    @Override
    public void onCreate(){
      super.onCreate();
    }
  }</code></pre><h3 id="ref">Ref</h3>
<ul>
<li><a href="https://colinch4.github.io/2020-11-25/Multidex/">https://colinch4.github.io/2020-11-25/Multidex/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Proguard 🛡]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-Proguard</link>
            <guid>https://velog.io/@jaeyunn_15/Android-Proguard</guid>
            <pubDate>Sun, 13 Jun 2021 15:02:17 GMT</pubDate>
            <description><![CDATA[<h3 id="proguard">Proguard</h3>
<blockquote>
<p>코드를 난독화 및 최적화 시켜주는 오픈 소스 툴</p>
</blockquote>
<ul>
<li>무료 자바 클래스 파일 축소기, 최적화기, 난독화기, 프리버레이터.</li>
<li>사용되지 않는 클래스, 필드, 방법, 속성을 검출해 제거한다.</li>
<li>bytecode를 최적화하고 사용하지 않는 지시사항을 제거한다.</li>
<li>짧은 의미 없는 이름을 사용하여 나머지 클래스, 필드, 방법의 이름을 바꾼다.</li>
</ul>
<h3 id="필요-이유">필요 이유</h3>
<p>자바는 JVM위에서 바이트 코드 형태로 컴파일 된다. 
이때, 컴파일 된 코드에서 자바 소스코드 정보가 그대로 포함되어 있기에 디컴파일을 하면 쉽게 코드를 얻을 수 있다. 그렇기에 디컴파일 시에 알아볼 수 없도록.</p>
<ul>
<li>코드 난독화로 인해 디컴파일 시 본인 코드 노출을 방지할 수 있다.</li>
<li>불필요한 메서드를 제거하여 멀티덱스를 피할 수 있다.</li>
</ul>
<h4 id="멀티덱스multidex">멀티덱스(Multidex)..?</h4>
<ul>
<li>안드로이드 앱을 구성하는 코드는 컴파일 되어 덱스(dex)파일로 만들어진다.</li>
<li>하나의 덱스파일에는 최대 65536개의 메서드만 참조할 수 있다.</li>
<li>만약 프로젝트의 코드가 65536개의 메소드를 초과하게 될 경우 덱스파일이 여러개 생성된다.</li>
<li>그러면 멀티덱스를 사용하여 컴파일 할 수 있지만, 빌드 과정에서 앱 내의 파일을 여러 개의 덱스파일로 나눠야 하므로 빌드 속도가 느려지고 apk용량이 커진다.</li>
</ul>
<h3 id="proguard를-사용하지-않았을-시-문제점">Proguard를 사용하지 않았을 시 문제점</h3>
<ul>
<li>프로젝트 코드가 난독화가 되지 않아 디버그 시에 코드 노출이 우려된다.</li>
<li>불필요 코드가 앱 컴파일 시 포함되어 불필요하게 앱의 용량이 증가한다.</li>
<li>불필요 코드가 컴파일에 포함되기에 개발시 메서드 65536개 초과로 멀티덱스 사용을 피할 수 없다.</li>
</ul>
<h3 id="장점">장점</h3>
<ul>
<li>프로젝트 코드 난독화</li>
<li>프로젝트에서 사용하지 않는 메서드 제거</li>
<li>불필요한 메서드 제거로 인해 멀티덱스 사용하지 않을 수 있음</li>
</ul>
<hr>
<h3 id="apk-빌드-과정">APK 빌드 과정</h3>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/9a39c591-5828-4db4-9e8e-2a97bfe6e68a/image.png" alt=""></p>
<p>앱 관련(R.java, 소스코드, 자바 인터페이스) 코드들은 컴파일을 거쳐 </p>
<ol>
<li><strong>바이트 코드로 전환</strong>되고 </li>
<li><strong>인증을 포함한 패키징 과정</strong>을 통해 생성된다.</li>
</ol>
<p>1️⃣ Android Manifest, xml 등 모든 리소스 파일들이 컴파일되어 R.java 파일을 생성하여 AAPT 파일을 생성하고 특정 resourceid로 매핑시킨다.</p>
<p>2️⃣ .aidl interface를 자바 인터페이스로 만들어준다.</p>
<p>3️⃣ javac는 앱 관련 코드(R.java 파일, 소스코드, 자바 인터페이스)를 컴파일 하여 바이트코드(.class파일)로 변환되며 이때 프로가드 과정이 일어난다. <strong>(dex파일 생성)</strong></p>
<p>4️⃣ dex + 3rd party library 클래스 파일 -&gt; .dex file</p>
<p>5️⃣ AAPT + .dex file -&gt; apk로 패키징 -&gt; .apk 생성</p>
<p>6️⃣ debug 또는 release 용 keystore로 인증 진행 -&gt; 인증된 .apk 생성</p>
<p>6️⃣-1️⃣ release 모드로 인증 시 zipalign tool을 이용하여 align 시켜줌(align시 메모리 효율성을 높여줌)</p>
<h3 id="ref">Ref</h3>
<ul>
<li><a href="https://iw90.tistory.com/298">https://iw90.tistory.com/298</a></li>
<li><a href="https://dwenn.tistory.com/95">https://dwenn.tistory.com/95</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] WebRTC 📲]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-WebRTC</link>
            <guid>https://velog.io/@jaeyunn_15/Android-WebRTC</guid>
            <pubDate>Sun, 13 Jun 2021 10:16:42 GMT</pubDate>
            <description><![CDATA[<p>최근 여러 서비스에서 WebRTC를 사용하여 많은 서비스를 제공한다는 글을 보았다. 
화상회의, 소셜 소개팅 등 여러 부분에서 쉽게 쓰일 수 있기에 최근 인기를 끌고 있다. WebRTC라는 단어를 하도 많이 보게되서 내가 정리를 해두려 한다.</p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/f9301bb9-c746-43c0-a735-92beacdfece5/image.png" alt=""></p>
<h3 id="webrtc-">WebRTC ?</h3>
<ul>
<li>Web Real-Time Communication</li>
<li>웹 어플리케이션 및 사이트들이 별도의 소프트웨어 없이 음성, 영상 미디어 혹은 텍스트, 파일 같은 데이터를 브라우저끼리 주고 받을 수 있게 만든 기술.</li>
<li>WebRTC로 구성된 프로그램들은 별도의 플러그인이나 소프트웨어 없이 P2P 화상회의 및 데이터 공유를 한다.</li>
</ul>
<blockquote>
<p>웹 브라우저 상에서 어떠한 플러그인도 필요없이 음성 채팅과 화상 채팅, 데이터 교환까지 가능한 기술</p>
</blockquote>
<h4 id="같이-알아야-할-용어-개념">같이 알아야 할 용어 개념</h4>
<ul>
<li>data stream, STUN/TURN servers, signaling, JSEP, ICE, SIP, SDP, NAT, UPD/TCP, network socket 등</li>
</ul>
<h3 id="통신-원리">통신 원리</h3>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/98f3696f-002b-4879-b3b7-59e8d0788ec8/image.png" alt="">
WebRTC 기술은 <strong>P2P 통신에 최적화</strong>되어 있다.
WebRTC에 사용되는 기술은 여러 가지가 있지만 크게 3가지의 클래스에 의해 실시간 데이터 교환이 일어난다. </p>
<ul>
<li>MediaStream : 카메라와 마이크 등의 데이터 스트림 접근</li>
<li>RTCPeerConnection : 암호화 및 대역폭 관리 및 오디오, 비디오 연결</li>
<li>RTCDataChannel : 일반적인 데이터의 P2P 통신</li>
</ul>
<p>이 3가지의 객체를 통해 데이터 교환이 이뤄지며 RTCPeerConnection들이 
적절하게 데이터를 교환할 수 있게 처리해주는 과정을 <strong>시그널링</strong>(Signaling)이라고 한다.</p>
<p>위 그림은 시그널링을 하는 과정이며 PeerConnection은 2 명의 유저가 스트림을 주고 받는 것이므로 연결을 요청하는 <strong>콜러(Caller)</strong>와 연결을 받는 <strong>콜리(Callee)</strong>가 존재한다.</p>
<p>콜러와 콜리가 통신을 하기 위해서는 중간 역할을 해주는 서버가 필요하고 서버를 통해 <strong>SessionDescription</strong>을 서로 주고 받아야한다.</p>
<hr>
<h3 id="장점">장점</h3>
<h4 id="latency가-짧다">Latency가 짧다.</h4>
<p>흔히 우리가 아는 인스타라이브, 유튜브라이브, 트위치 등은 RTMP를 사용하여 실시간 스트리밍을 한다.
RTMP보다 WebRTC는 낮은 Latency를 가지고 있고 거의 지연 시간 없는 REAL-TIME 성향을 갖고 있따.</p>
<h4 id="별-다른-소프트웨어-없이-실시간-커뮤니케이션이-가능하다">별 다른 소프트웨어 없이 실시간 커뮤니케이션이 가능하다.</h4>
<p>웹/앱으로 방송을 키고 싶을 때, 별도의 플러그인이나 미디어 송출 관련 소프트웨어 설치가 필요없다.</p>
<h4 id="개발-시-진입-장벽이-낮다">개발 시 진입 장벽이 낮다.</h4>
<hr>
<h3 id="단점">단점</h3>
<h4 id="크로스-브라우징-문제">크로스 브라우징 문제</h4>
<p>WebRTC는 현재 크롬,오페라,파이어폭스 뿐아니라 안드로이드, IOS 등 브라우저, 앱에서 활용가능하다. 그러나 최신 버전을 사용하지 않는 사용자는 사용이 불가능하다는 단점이 있다.  (IE 지원은 안한다고 한다)</p>
<h4 id="stunturn-서버-필요">STUN/TURN 서버 필요</h4>
<p>P2P 통신을 위해서는 사용자의 IP 주소를 알아야한다.
하지만, 대부분의 사용자는 방화벽 등을 사용하고 다른 네트워크 상에서 연결이 이뤄지기 위해서는 STUN/TURN서버가 꼭 필요하다.</p>
<p><a href="https://gh402.tistory.com/45">관련 개념을 정리해두신 블로그</a></p>
<hr>
<p>추가 설치를 덕지덕지해야하는 activex, flash를 지워버리고 당당하게 스트리밍 기술로 상용화된 WebRTC에 대해서 실제로 작업을 해보면서 더 익혀봐야 할것 같다.</p>
<p>그리고 충분한 네트워크 공부가 바탕이 되어야 깊은 이해가 될 수 있을 것 같다.</p>
<h2 id="🆒">🆒</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] [번역] A Garbage Collection Story ]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-A-Garbage-Collection-Story-%EB%B2%88%EC%97%AD</link>
            <guid>https://velog.io/@jaeyunn_15/Android-A-Garbage-Collection-Story-%EB%B2%88%EC%97%AD</guid>
            <pubDate>Sun, 13 Jun 2021 03:12:48 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>해당 글은 <a href="https://proandroiddev.com/a-garbage-collection-story-2421b96e4c84">A Garbage Collection Story</a>를 번역한 글이며 아주 조금의 첨언이 되어있는 글입니다. </p>
</blockquote>
<p>출처는 <strong>ProAndroidDev</strong>
<img src="https://images.velog.io/images/jaeyunn_15/post/00fe3bd1-3c72-4026-b2df-26bfcf3fb4a3/image.png" alt=""></p>
<p>몇몇 안드로이드 관련 아티클을 찾아보는 곳 중 공식 미디엄 말곤 proandroiddev를 많이 보게 된다. 
생각해보지 못한 부분에 대한 글 혹은 이것도 공부하면 좋겠다 싶은 글이 많다.</p>
<h4 id="🆗-아무튼-오늘-번역할-이야기는-안드로이드-gc-이야기다">🆗 아무튼 오늘 번역할 이야기는 안드로이드 GC 이야기다.</h4>
<p>JVM의 GC는 공부하였지만 Android에서 GC는 다른 이야기일 것이다. 
왜? 
Android는 JVM이 아닌 DVM(Dalvik Virtual Machine)에서 동작한다. 
DalVik부터 ART까지 GC의 발전 역사를 알아보자.</p>
<h3 id="introduction">Introduction</h3>
<p>여러 차들이 주차되어 있는 주차장을 떠올려보자.
<img src="https://images.velog.io/images/jaeyunn_15/post/8ab698db-40d2-42d5-aeca-87afe0dcc551/image.png" alt=""></p>
<p>차들이 들어오고 나가며 한 대당 하나의 자리를 차지하게 된다.
물론 승용차가 아닌 대형 트럭이라면 여러 자리를 차지할 수도 있다.
사람들은 아마 이 부분에서 화를 낼 수 있다.</p>
<p>이게 바로 <strong>메모리</strong>다.</p>
<p>Garbage Collector라고 부르는 <strong>Recycler Bill</strong>이 있다. 
일생 단 하나의 목적은 주차장의 쓰레기를 모으는 것이다.</p>
<p>차들이 주차장을 떠날 때 그들은 Bill이 쓰레기를 처리할 수 있도록 잘 모아둔다.
뭐 모든 사람이 잘 모아두진 않는다. 누군가는 쓰레기를 모아서 가방에 넣어두지 않고 간다.
대신, 그들은 쓰레기 더미를 잘 모아두고 떠난다. </p>
<p>불행하게도, Bill은 이 일에 대한 충분한 급여를 받지는 못해서 쓰레기 더미 조차 치울 수는 없습니다.
쓰레기는 이때 애매하게 주차장의 일부를 차지하게 됩니다.</p>
<p>이게 바로 <strong>메모리 누수</strong>이다.</p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/48b1de4f-a31f-4e62-b1f2-3ac2694b22be/image.png" alt=""></p>
<p>새로운 차들이 와서 주차하려 할 때, 공간이 충분하지 않을 수 있게 된다..
주차 공간은 터지게 되고 Bill 역시 머리가 터지겠지? 🤯</p>
<p>이게 바로 <strong>OutOfMemoryException</strong>이다.</p>
<p>Bill은 단순 Garbage Collector 그 이상이다.
그의 손에는 주차장의 운명이 달릴 정도다..🆒</p>
<hr>
<p>우리가 할 일이 이제 뭘까?
재활용하는 Bill의 일상을 따라서 그가 주차장을 잘 관리하는 best garbage collector가 되도록.... 한 번 알아보자</p>
<p>(대충 여기까지가 GC의 이유와 목적을 주차장에 비유해서 표현한 부분이다.)</p>
<h3 id="dalvik-bill-up-until-android-44">Dalvik Bill (up until Android 4.4)</h3>
<p>주차장의 상황이 좋지 않다는 것 정도는 우리 안다.</p>
<p>정~말 필요한 차들만 주차를 해야 한다.</p>
<p>더욱이, Bill은 쓰레기 수거를 위해 청소가 끝날 떄 까지 어떠한 차도 들어오고 나갈 수 없도록 하기에 이 부분은 다소 사람들을 짜증나게 할 수 있다.</p>
<p>Bill은 이러한 고충을 어떻게 해결할까?</p>
<p>여기서 그의 특별한 기술인 <strong>Mark and Sweep</strong>가 나타난다.</p>
<p>우선, Bill은 자주 쓰레기를 수거하는 것이 좋지 않다는 것을 알아내었다. 대신, 그는 주차장이 꽉 찰 때까지 기다린다. 그리고 꽉차면 그는 쓰레기 수집을 한다.</p>
<p>두 가지 단계로 쓰레기를 수집하는데,
1️⃣ 그는 주차장을 돌아다니면서 차들이 있는 곳을 <strong>marking한다</strong>. 이 과정에서 주차장 내부의 움직인은 <strong>잠시 멈춤</strong>을 한다.</p>
<p>2️⃣ 어떠한 위치에 차들이 있는지 알았따면, 그는 마킹되지 않는 주차 공간의 쓰레기들을 <strong>sweep하게</strong> 된다. 그는 여전히 동일 급여를 받기에 packing되지 않는 쓰레기는 수거하지 않는다.😂</p>
<p>많이 나아졌음에도 bill은 여전히 문제를 갖고 있다.</p>
<p>그가 쓰레기 수집을 한 이 후에, 주차장에 많은 틈이 남아 있다.
군대가 와서 여러 탱크가 주차 공간을 요구한다면?? 👀</p>
<p>이 문제는 <strong>Heap Fragmentation</strong> 이다.</p>
<p>시간이 지난 후 bill은 해결책을 가져온다.</p>
<p>밤에, 주차장에 유동 트래픽이 많지 않는 때에, <strong>그의 미친 힘으로 차들을 재정렬</strong>하고 그럼으로 인해 <strong>연속적인 주차 공간을 만들어 낸다</strong>.😬 </p>
<p>이것이 애플리케이션의 백그라운드에서 발생하고 있는 heap compaction(힙 압축)이다.</p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/10b6789b-327a-4a2e-ae5f-23a7c4ccc9b8/image.png" alt="">
realign을 하고 나면 이런식의 주차 공간이 생길 것이다. (100%는 아니지만)</p>
<p>그러나 여전히 문제는 있다.
군대가 낮 시간에 오면?? 주차 공간은 아마.. 폭발할것이다🤮</p>
<h3 id="art-bill">ART Bill</h3>
<p>몇년 동안, Bill 그의 기술을 연마했다.</p>
<p>이제, Bill은 승진을 해서 *<em>낮 시간 동안에도 주차 공간을 realign할 수 있게 *</em>되었다. (승진하면 힘이 더 쎄지는 군)
군대가 탱크를 끌고 오더라도 bill은 수용이 가능해졌다.</p>
<p>이것이 애플리케이션이 포그라운드에 있더라도 발생하는 <strong>힙 압축</strong>이다.</p>
<p>주차 공간은 더 발전하였고 가격은 내려갔으며 사람들은 이제 이곳에 주차하는 것을 망설이지 않는다.</p>
<p><strong>주차 공간은 더 이상 pause 상태를 갖지 않고 bill은 주차 공간을 marking할 수 있다.
전체 garbage collection 과정은 3배나 빨라졌다.👍</strong></p>
<p>게다가, 주차 공간의 디지털화로 인해 bill은 더욱 쉽게 주차 공간에서 얼마나 차들이 머물고 간지 싑게 추적할 수 있게되었다. 
이러한 지식들로, bill은 차들을 그룹화 시킬 수 있게 되었다.</p>
<p>여기엔 3가지의 <strong>heap generation</strong>가 있다.</p>
<ul>
<li>Young Generation (Eden, S0, S1)</li>
<li>Old Generation</li>
<li>Permanent Generation</li>
</ul>
<p>자동차들이 오랜 시간동안 주차를 한다면 bill은 차들을 old generation으로 옮긴다.</p>
<p>각 generation은 주차 된 차량이 차지 할 수 있는 공간에 대한 자체 상한선이 있다.
만약 generation에서 한계에 도달한다면, bill은 해당 generation을 위한 garbage collection을 하게 된다.</p>
<hr>
<p>여기까지  이야기의 전부이다.</p>
<p>우리가 흔히 JVM을 공부할 때, GC를 공부하게 되고 
Young Generation(Eden, S0, S1), Old Generation, Permanet Generation를 공부하고 minor gc, major gc를 공부한다.</p>
<p>해당 글은 주차장과 주차장을 관리하는 bill을 갖고서 gc를 설명하였고 Dalvik에서의 GC와 ART에서의 GC의 차이도 살펴보았다.</p>
<p>잠시 정리해보자.</p>
<h4 id="dalvik">Dalvik</h4>
<ul>
<li>Mark &amp; Sweep과정을 통해 쓰레기를 수집하자.</li>
<li>Heap Fragmentation이 발생한다. 이는 Heap Compaction으로 해결가능한데 백그라운드에서 가능하다.</li>
<li>결국 백그라운드가 아니라면 불가능하다는 문제를 마주한다.</li>
</ul>
<h4 id="art">ART</h4>
<ul>
<li>(발전) Heap Compaction을 낮에도 할 수 있다. 포그라운드에서도 할 수 있다는 것이다. </li>
<li>(발전) 더 이상 pause 상태로 주차장을 멈추고 mark&amp;sweep을 하지 않아도 된다. 3배나 빨라졌다.</li>
<li>(새로운) 주차 공간을 추적하여 오래 머문 차, 이제 막 들어온 차 이렇게 분류도 할 수 있어서 그룹화 할 수 있게 된다. Generalization</li>
</ul>
<p>Dalvik에서 ART로 넘어가면서 발전 된 것들과 새롭게 얻게 된 기술, 능력들이 있다. 
이를 통해 우린 Android에서 GC가 어떤 발전을 이루었는지 어떤 기능을 갖추었는지 알 수 있다.</p>
<p>deep dive를 하고 싶다면, 아래 영상을 참고하자.👊
<a href="https://www.youtube.com/watch?v=oKMsPrDMprE">Trash Talk: The Evolution of Android Garbage Collection</a></p>
<h3 id="ref">Ref</h3>
<ul>
<li><a href="https://proandroiddev.com/a-garbage-collection-story-2421b96e4c84">A Garbage Collection Story</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Android 위치 권한 변경 사항 🧭]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-Android-%EC%9C%84%EC%B9%98-%EA%B6%8C%ED%95%9C-%EB%B3%80%EA%B2%BD-%EC%82%AC%ED%95%AD</link>
            <guid>https://velog.io/@jaeyunn_15/Android-Android-%EC%9C%84%EC%B9%98-%EA%B6%8C%ED%95%9C-%EB%B3%80%EA%B2%BD-%EC%82%AC%ED%95%AD</guid>
            <pubDate>Fri, 11 Jun 2021 05:25:17 GMT</pubDate>
            <description><![CDATA[<p>Android 11 버전 여러 업데이트 사항 중 <strong>개인정보 보호기능</strong>에서 크게 달라졌다는 글을 보았다.</p>
<p>곧 Android 12가 출시 되겠지만 그래도... </p>
<p>여러 프로젝트를 해보면서 지도에서 사용자 위치 접근에 대한 퍼미션을 많이 다뤘었다. 
근데 정작 허용 여부를 물어보고 허용/비허용에 따른 동작만 다루었을 뿐, 허용에 대한 상세적인 이야기를 다뤄본 적이 없다.</p>
<p>그래서 Android에서의 위치 권한을 이번 글에서 다루고자 한다.</p>
<hr>
<blockquote>
<p><a href="https://scshim.tistory.com/270">안드로이드 6,10,11 위치 권한 변경</a>
위 글에서 충분히 자세히 설명을 해주시고 있고 난 여기에 덧붙여 설명하려 한다.</p>
</blockquote>
<p>우선 위치 권한 퍼미션의 역사를 살펴보면
크게 Android 6.0 이전과 이후로 나눠진다.</p>
<h3 id="before-android-60-122">Before Android 6.0 (1~22)</h3>
<p>Android 6.0 이전에는 앱에서 필요한 권한을 사용자로부터 요구할 때 <strong>어플을 설치할 때 요구</strong>하였다.</p>
<h3 id="after-android-60-23-마시멜로">After Android 6.0 (23-마시멜로)</h3>
<p>Android 6.0 부터는 앱에서 필요한 권한이 있을 때 사용자로부터 권한을 그때 받게 되었다. </p>
<p>즉, <strong>위치 권한이 필요한 시점에 사용자에게 요청</strong>할 수 있었다.</p>
<h4 id="manifest">manifest</h4>
<pre><code>&lt;uses-permission android:name=&quot;android.permission.ACCESS_COARSE_LOCATION&quot; /&gt;
&lt;uses-permission android:name=&quot;android.permission.ACCESS_FINE_LOCATION&quot; /&gt;</code></pre><p><strong>ACCESS_COARSE_LOCATION</strong> : 네트워크를 이용하여 단말기 위치 식별
<strong>ACCESS_FINE_LOCATION</strong> : GPS와 네트워크를 이용하여 단말기 위치 식별
(더 정확한 위치는 ACCESS_FINE_LOCATION이라고 한다.)</p>
<h4 id="위치-권한-요청-코드">위치 권한 요청 코드</h4>
<pre><code>int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);

if(permissionCheck == PackageManager.PERMISSION_DENIED){ //위치 권한 확인

    //위치 권한 요청
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0);
}</code></pre><p><img src="https://images.velog.io/images/jaeyunn_15/post/89a5b249-6294-412f-9115-b33e34053156/image.png" alt="">
이러한 이미지를 통해 허용과 비허용을 체크할 수 있다.
그리고 그 상태에 따라 개발자는 분기처리를 하게 된다.</p>
<hr>
<h3 id="android-8-26">Android 8 (26)</h3>
<p>Android 26에서는 위치 권한 변경 사항이라기보단 백그라운드 위치 제한을 두게 된다! </p>
<blockquote>
<p><a href="https://developer.android.com/training/permissions/usage-notes?hl=ko#version_specific_details_permissions_in_m">공식문서</a> say
기기 성능 개선을 위해 포그라운드 실행 중이지 않은 앱의 특정 동작을 제한한다.</p>
</blockquote>
<h4 id="android-백그라운드-위치-제한">Android 백그라운드 위치 제한</h4>
<ul>
<li><code>startService()</code>를 사용하여 백그라운드 서비스 생성이 허용되지 않은 시점에 접근하려 할 경우 <strong>illegalStateException</strong>을 발생시킨다고 한다.</li>
<li>배터리, 사용자 환경 및 시스템 상태를 유지하기 위해 Android 8.0를 실행하는 기기에서 백그라운드 앱 사용 시 위치 업데이트를 받는 빈도가 줄어듭니다. 라고 하면서 제한을 시키기 시작한다...</li>
</ul>
<p>위치 권한 설정 여부와 관계없지만 Android 8에서 나타난 백그라운드 접근 제한을 시작으로 10부터는 백그라운드 위치 접근을 아예 분리시켜 놓게 된다!
이야기의 흐름 맥락 상 알고있으면 좋을 내용이다.</p>
<hr>
<h3 id="android-10-29">Android 10 (29)</h3>
<p>Android 10에서는 백그라운드 위치 권한과 포그라운드 위치 권한으로 나뉘었다.</p>
<p><strong>백그라운 위치 권한</strong> - 화면이 보이지 않지만 위치는 체크 하고 있는
<strong>포그라운 위치 권한</strong> - 앱의 화면이 보이는 상태에서 위치를 체크하게 되는</p>
<p>그래서 백그라운드 위치 권한 요청을 하려면 Manifest에 한 가지 더 추가해줘야 한다.</p>
<pre><code>&lt;uses-permission android:name=&quot;android.permission.ACCESS_BACKGROUND_LOCATION&quot; /&gt;</code></pre><p>이렇게 지정해두게 된다면 권한 허용 여부를 물어보는 과정에서 Android 6과는 다르게 나타난다.</p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/85ca4546-81d7-45f2-b5be-e2980103d2fb/image.png" alt=""></p>
<p>위의 사진에서 볼 수 있듯 3가지의 경우로 분기 처리가 된다.</p>
<ul>
<li>*<em>항상 허용 (Allow all the time) *</em><ul>
<li>백그라운드, 포그라운드 모두 허용</li>
</ul>
</li>
<li><strong>앱 사용 중에만 허용 (Allow only while using the app)</strong><ul>
<li>포그라운드만 부분 허용</li>
</ul>
</li>
<li><strong>거부 (deny)</strong><ul>
<li>모두 거부</li>
</ul>
</li>
</ul>
<p>그렇다면 기존에 Android 6 이후에 Background 위치 권한 요청을 하지 않는다면 무슨 일이 일어날까?</p>
<p>여러 영향을 생각해봐야 OS 버전 업데이트를 하더라도 어플 문제가 없지 않을까?</p>
<blockquote>
<p>역시나 정리를 해주신 분들이 있다 <a href="https://brunch.co.kr/@huewu/11">Android Q 새로운 위치 접근</a> 
위 글이 원문이다.</p>
</blockquote>
<h4 id="개발자-입장에서의-대응이-궁금해서-가져와봤다">개발자 입장에서의 대응이 궁금해서 가져와봤다.</h4>
<p>1️⃣ 사용자가 앱을 사용하는 동안에만 위치 정보를 확인하는 경우</p>
<ul>
<li>사용자 근처에서 특정 장소를 찾는 경우 (해당 앱이 사용자 포커스를 갖고 있는 경우) 기기 위치 정보를 필요로 할 수 있다. </li>
<li>Target SDK가 Q(10) 미만이라면, 시스템에서 ACCESS_BACKGROUND_LOCATION 권한을 자동으로 추가하게 되고 결국 불필요한 &#39;항상 허용&#39; 옵션이 표시된다.</li>
<li>Target SDK를 Q(10)으로 올리게 될 경우, ACCESS_BACKGROUND_LOCATION 권한을 완전히 제외할 수 있다.</li>
</ul>
<p>2️⃣ 앱이 포그라운드 서비스를 통해 빈번하게 사용자 위치 정보를 확인하는 경우</p>
<ul>
<li>네비게이션 서비스가 대표적이다. (앱이 포커스를 갖고 있지 않더라도 지속적으로 위치를 확인해야 하는 경우)</li>
<li>이런 경우엔 포그라운드 서비스를 이용하여 백그라운드 실행 및 위치 제한을 피할 수 있다. 근데 이런 경우도 이런저런 이유로 포그라운드 서비스 남용을 막기 위해 &#39;location&#39;이 포함된 경우 포그라운드 서비스를 통해 기기 위치 정보를 확인할 수 있다. </li>
<li>ACCESS_BACKGROUND_LOCATION 권한을 요청할 필요가 없고, 사용자가 &#39;앱 사용 중에만 허용&#39; 옵션을 선택한 경우에도 앱이 정상적으로 동작한다.</li>
</ul>
<p>3️⃣ 앱이 백그라운드에서 위치 정보를 확인하는 경우</p>
<ul>
<li>위치 기반으로 사용자 위치를 알아내서 광고를 하는 경우! </li>
<li>사용자가 &#39;앱 사용중에만 허용&#39; 옵션을 선택한 경우, 사용자가 앱을 끈 경우 위치 정보를 확인할 수 없다.... 이런 경우 ACCESS_BACKGROUND_LOCATION 권한을 요청해야 한다. 기기 위치 권한은 있지만 백그라운드 위치 권한이 없는 경우를 처리하는 별도 로직을 구현하고 권한이 필요한 이유를 잘 설명하는 UX가 필요하다! </li>
</ul>
<h4 id="정리">정리</h4>
<ul>
<li><p>내가 만든 어플의 타겟이 Android 10 (API 29) 이상을 타겟한다. 근데 백그라운드 위치 정보 엑세스는 필요하지 않다?</p>
<ul>
<li>ACCESS_BACKGROUND_LOCATION 권한을 MANIFEST에서 삭제!</li>
</ul>
</li>
<li><p>내가 만든 어플의 타겟이 Android 10 (API 29) 이상을 타겟한다. 그리고 백그라운드 위치 정보를 필요로 한다! </p>
<ul>
<li>사용자에게 왜 필요한지를 알려주고 별도 로직을 구현하여 요청해야 한다.</li>
</ul>
</li>
</ul>
<p>백그라운드 정책 관련하여 더 궁금하다면 <a href="https://developer.android.com/training/location/background?hl=ko">공식 문서</a>를 살펴보자.
<del>(개인적으로는 백그라운드 위치 접근에 대해 아주 많</del>이 제한,제약을 두려고 하는 것 같다)~~</p>
<h4 id="위치-권한-여부-코드">위치 권한 여부 코드</h4>
<pre><code>int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);

if(permissionCheck == PackageManager.PERMISSION_DENIED){ //포그라운드 위치 권한 확인

    //위치 권한 요청
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0);
}


int permissionCheck2 = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION);

if(permissionCheck == PackageManager.PERMISSION_DENIED){ //백그라운드 위치 권한 확인    
    //위치 권한 요청
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, 0);
}</code></pre><hr>
<h3 id="android-11-30">Android 11 (30)</h3>
<p>Android11에서는 사용자가 선택할 수 있는 위치 권한 옵션이 더 세분화 되었다. 😂</p>
<p>앞서 살펴보았듯
Android 10에서는 [항상 허용, 앱 사용중만 허용, 거부] 이렇게 3가지가 있었다.
Android 11에서는 [항상 허용, 앱 사용중만 허용, 이번만 허용, 거부] 이렇게 4가지로 나누어지게 되었다.</p>
<h4 id="이번만-허용">이번만 허용???</h4>
<ul>
<li>말 그대로 일회성 권한이다. </li>
<li>오랜 시간 사용 안한 앱은 권한이 자동 재설정된다. 권한을 필요로 하는 백그라운드에서 주로 돌아가는 앱은 자동 재설정 되는 것을 막게 사용자에게 요청 필요.</li>
<li>사용자 개인 정보 보호 강화를 위해 추가된 방식!</li>
<li>사용자가 일회성 위치 엑세스 권한을 추가하고 사용자가 백그라운드 위치 엑세스 권한을 부여하는 방식.</li>
</ul>
<p>Android 11에서의 위치 권한 요청 화면이다.
<img src="https://images.velog.io/images/jaeyunn_15/post/cbf1402c-16f2-4da2-bf6b-8bbe4e495e6a/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-06-11%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.56.22.png" alt=""></p>
<h4 id="항상-허용은-어디-갔나요">항상 허용은 어디 갔나요?</h4>
<ul>
<li>Android 11에서는 <em>즉시 &#39;항상 허용&#39; 옵션은 사용할 수 없다.</em></li>
<li>대신 위에서 볼 수 있듯, <strong>설정에서 액세스를 허용하세요.</strong>를 눌러서 설정 창에 가서 직접 허용 해야 <strong>&#39;항상 허용&#39;</strong>이 가능하다!</li>
<li>이것 역시 사용자에게 더 많은 선택 권한을 준 것으로 볼 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] DiffUtil이 뭔지 설명해주시겠어요? 👀]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-DiffUtil%EC%9D%B4-%EB%AD%94%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%8B%9C%EA%B2%A0%EC%96%B4%EC%9A%94</link>
            <guid>https://velog.io/@jaeyunn_15/Android-DiffUtil%EC%9D%B4-%EB%AD%94%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%8B%9C%EA%B2%A0%EC%96%B4%EC%9A%94</guid>
            <pubDate>Fri, 11 Jun 2021 01:48:41 GMT</pubDate>
            <description><![CDATA[<p>면접에서 참 많이 받게 되는 질문이다.</p>
<p>면접을 떠나서 안드로이드 개발자는 안드로이드 어플 개발을 하면서 RecyclerView를 정말 많이 만들어보고 다양한 adpater를 사용해본다.</p>
<p>수 많은 리스트의 데이터의 내용 중 변화가 생기게 된다면 우린 <code>notifyDataChanged()</code>를 통해 변화를 알려주게 된다.
그러나 notifyDataChanged()를 사용하면 새로운 item 인스턴스를 생성하기위해 비용이 많이 든다.</p>
<p><em>&#39;RecyclerView 성능 개선&#39;</em> 이라고 검색만 해도 수많은 블로그 글들에서 notifyDataChaged()를 사용하지 말고 변경되는 특정 데이터에만 변경을 알려주자! 라고 한다. </p>
<p>*<em>🖐 그럼 변경이 단 한개가 아니고 100만개의 리스트 데이터중 7만개가 변경되었고 위치는 그때 그때 다르다고 하자. *</em></p>
<p>우리가 7만개를 다 계산해서 notifyItemChanged()를 날려줄까? 
여러 개니까 notifyItemRangeChanged(positionStart, itemCount)를 날려줘? 위치는 다 다른데? </p>
<p>저러한 연산들이 무조건 비효율적이란게 아니다! 상황에 따라 더 나을 수도 있지만 주로 DiffUtil의 성능이 좋다. (그 이유는 앞으로 설명하겠지만)</p>
<p>그럼 알아보자.</p>
<hr>
<h3 id="diffutil">DiffUtil</h3>
<blockquote>
<p>두 목록의 차이를 계산하고 old item에서 new item으로 목록이 변환 할 때 업데이트 되는 작업 목록을 출력하는 유틸리티 클래스</p>
</blockquote>
<ul>
<li><strong>RecycerView에 새로운 리스트가 들어올 경우, 해당 리스트를 탐지하고 자동으로 변경해주는 역할을한다.</strong></li>
<li>Eugene W.Myers의 difference 알고리즘을 사용한다.</li>
<li>목록 변환을 위한 최소의 업데이트 수를 계산.</li>
<li>O(N + D^2)의 시간 복잡도를 갖는다. 
N:추가/제거 된 항목 수, D : 스크립트 길이</li>
</ul>
<h4 id="그래서-이점은">그래서 이점은?</h4>
<ul>
<li>변한 아이템을 탐지하고, 내부적으로 알아서 notify해주기에 아이템 변경에 대해 고려를 덜 할 수 있다.</li>
</ul>
<p>더 나아가서 표현하자면</p>
<p><strong>💡 DiffUtil을 사용하여 데이터 갱신을 위임하자.</strong></p>
<h4 id="lets-use-it">Let&#39;s use it.</h4>
<pre><code>class SubjectDiffUtilCallback(
    private val oldTiles: List&lt;Subject&gt;,
    private val newTiles: List&lt;Subject&gt;
) : DiffUtil.Callback() {

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldSubjects[oldItemPosition] == newSubjects[newItemPosition]
    }

    override fun getOldListSize(): Int {
        return oldSubjects.size
    }

    override fun getNewListSize(): Int {
        return newSubjects.size
    }

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldSubjects[oldItemPosition].number == newSubjects[newItemPosition].number
    }
}</code></pre><p>예제는 DiffUtil.Callback에서 주로 쓰이는 4개의 메서드를 구현해놓았습니다.</p>
<p>DiffUtil 클래스 사용을 위해서 바뀌기 전 리스트와 바뀐 후 리스트 2가지를 모두 알고 있어야 한다.</p>
<p>원래 DiffUtil.Callback은 4개의 추상 메서드와 1개의 비추상 메서드로 구성되어있다.</p>
<p><strong>4가지 추상 메서드</strong></p>
<ul>
<li>areItemsTheSame(oldPosition:Int, newPosition:Int) : 두 객체가 동일한 항목을 나타내는지 확인</li>
<li>getOldListSize() : 바뀌기 전 리스트의 크기를 리턴한다.</li>
<li>getNewListSize() : 바뀐 후 리스트의 크기를 리턴한다.</li>
<li>areContentsTheSame(oldPosition:Int, newPosition:Int) : 두 항목의 데이터가 같은지 확인한다. 
해당 메서드는 areItemsTheSame()에서 true 판별이 난 항목에 대해서만 검사를 수행한다.</li>
</ul>
<p><strong>1가지 비 추상 메서드</strong></p>
<ul>
<li>getChangePayload(oldPosition:Int, newPosition:Int) : areItemsTheSame == true &amp;&amp; areContentsTheSame==false일 경우에 호출된다.</li>
</ul>
<h3 id="🔌-동작방식을-생각해보자">🔌 동작방식을 생각해보자.</h3>
<ol>
<li><p>우리가 DiffUtil.Callback()을 반환하는 커스텀 클래스를 생성해줘야한다. 위의 예시에서 SubjectDiffUtilCallback처럼!! 
그리고 반드시 areItemsTheSame()과 areContentsTheSame()를 포함한 4가지 추상메서드를 구현을 해줘야한다. 그래야 비교가 가능하다.</p>
</li>
<li><p>해당 부분을 adapter내에서 데이터를 setting하는 부분에 넣어준다. </p>
<pre><code>private fun calDiff(newTiles: MutableList&lt;Tile&gt;) {
     val subjectDiffUtilCallback = SubjectDiffUtilCallback(dataSet, newTiles)
     val diffResult: DiffUtil.DiffResult = DiffUtil.calculateDiff(tileDiffUtilCallback)
     diffResult.dispatchUpdatesTo(this)
 }</code></pre><p>이런식이라고 생각해보자.
subjectDiffUtilCallback으로 콜백 결과를 받고 이를 DiffUtil.calculateDiff로 넣어서 다시 결과를 받고 이를 업데이트 요청하게 된다.
이는 adapter내에 정의된 메서드이며 adapter에게 변경을 알린다.</p>
</li>
</ol>
<h3 id="💢-조심할-점">💢 조심할 점</h3>
<ul>
<li>목록이 많으면 작업이 상당히 오래 걸릴 수 있기에 백그라운드 스레드에서 실행을 설정하고 DiffUtil.DiffResult를 가져와서 메인스레드에서 RecyclerView에 적용하는게 좋다.</li>
<li>구현 제약으로 목록의 최대 크기는 2²⁶개로 제한 되어 있다고 한다.</li>
</ul>
<h3 id="ref">Ref</h3>
<ul>
<li><a href="https://onemask514.tistory.com/48">https://onemask514.tistory.com/48</a></li>
<li><a href="https://gamjatwigim.tistory.com/120#recentComments">https://gamjatwigim.tistory.com/120#recentComments</a></li>
<li><a href="https://sohee1702.tistory.com/409">https://sohee1702.tistory.com/409</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Android dp dpi dpi sp 우린 뭘 써야 할까?]]></title>
            <link>https://velog.io/@jaeyunn_15/Android-Android-%EC%B9%98%EC%88%98-%EC%A0%95%EB%A6%AC-dp-dpi-dpi-sp-pt-</link>
            <guid>https://velog.io/@jaeyunn_15/Android-Android-%EC%B9%98%EC%88%98-%EC%A0%95%EB%A6%AC-dp-dpi-dpi-sp-pt-</guid>
            <pubDate>Thu, 10 Jun 2021 13:37:04 GMT</pubDate>
            <description><![CDATA[<p>Android는 해상도를 지원한다. 
그 종류는 많고 안드로이드 개발자라면 반드시 알아야 한다.</p>
<h3 id="왜-알아야-해">왜 알아야 해?</h3>
<p>디자이너와 협업을 해야하니까. 여러 화면에 대응해야 하니까</p>
<h4 id="🧐-다양한-디바이스-크기에-대응-그게-뭔데">🧐 다양한 디바이스 크기에 대응? 그게 뭔데?</h4>
<p>dp는 픽셀 독립 단위이다. <strong>(Device Independent Pixel)</strong>이라고도 하는데 말 그대로 _픽셀에 독립된 디바이스 라는 말로 다양한 안드로이드폰의 해상도를 지원하기 위해 나온 단위이다.
<img src="https://images.velog.io/images/jaeyunn_15/post/fc6a5dc8-023b-4f1a-967b-8242fdbf8ae9/image.png" alt="">
귀여운 안드로이드를 기준으로 설명을 해보겠다. 
화면이 작은 단말기도 존재하지만 큰 단말기도 너무 많다.
워낙 파편화가 심하다 보니 다양한 크기에 대응을 해야하고 그 기준도 어느정도 나눠져있다. 
위의 그림에서 보듯이 작은 화면과 큰 화면 모두에서 동일하게 안드로이드 아이콘을 볼 수 있게 만들 수 있다. </p>
<p>아래의 두 그림을 보면 왜 사용해야 하는지 명확히 이해 될 것이다.</p>
<h4 id="low-medium-high-density-화면에-픽셀-단위로-크기를-지정한-경우">Low, Medium, High-Density 화면에 픽셀 단위로 크기를 지정한 경우</h4>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/5d1dc9aa-da69-4d3e-a9e2-a152b3678078/image.png" alt=""></p>
<h4 id="low-medium-high-density-화면에-dp-단위로-크기를-지정한-경우">Low, Medium, High-Density 화면에 DP 단위로 크기를 지정한 경우</h4>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/f741624e-874f-49d8-9e28-cead34995bb8/image.png" alt=""></p>
<p>긴 말 필요없이 dp는 화면 별 대응이 가능하다.
더 자세하게 다양한 치수들을 알아보자.</p>
<hr>
<h4 id="dpi-dots-per-inch">dpi (Dots Per Inch)</h4>
<blockquote>
<p>1인치 당 픽셀 수. 
물리적인 단위인 1 inch(2.54cm)에 몇 픽셀이 들어가는가에 대한 단위</p>
</blockquote>
<p>Low density (120dpi) : ldpi
Medium density (160dpi) : <strong>mdpi (기본)</strong>
High density (240dpi) : hdpi
Extra High density (320dpi) : xdpi
xxhdpi : 480dpi
xxxhdpi : 640dpi</p>
<p>디자이너와 협업을 하다보면 디자이너가 휴대폰을 mdpi에 맞춰 작업한다고 하신다.
😅 아 그럼 160dpi 라고 알아들어야겠지?</p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/9045caee-ab11-4742-9d61-873fdc220269/image.png" alt=""></p>
<hr>
<h4 id="px-pixel">px (pixel)</h4>
<blockquote>
<p>스크린의 실제 픽셀 단위, 실제 크기나 밀도와 관련없다.
절대적 표시 단위이다.</p>
</blockquote>
<p>mdpi(기본값) = 160dpi이다.
여기서 공식을 하나 알고 가면 좋다.</p>
<p>개발을 하다보면 dp를 px로 혹은 px을 dp로 바꾸는 경우가 있다.</p>
<p>공식을 알고있다면 매우 편하다.
<code>dp = px * 단말 dpi / 기본 160</code> 
<code>px = dp * 기본 160 / 단말 dpi</code> 
이다. </p>
<p>이게 뭔소리냐고?</p>
<p>mdpi가 기본 값이라고 dpi 설명에서 보았다. (mdpi=160dpi)
즉, 기본값을 기본값으로 나누면 1dp = 1px인 것이다.</p>
<p>그럼 hdpi인 경우엔? 
hdpi는 240dpi였고 공식에 대입을 해보자.
<code>px = dp * 160/240</code>으로 나온다.
px = dp * 2/3 👉 <strong>1dp = 1.5px</strong>
<em>즉, hdpi를 1dp로 볼 때 1.5px이 된다.</em></p>
<p>이런 식으로 화면의 밀도에 따라 정해진 px값을 요리조리 바꿔가며 사용자에게 보여주게 된다.</p>
<p>ldpi : 1dp = 0.75px
mdpi : 1dp = 1px
hdpi : 1dp = 1.5px
xdpi : 1dp = 2px</p>
<p>이렇게 정리할 수 있다.</p>
<hr>
<h4 id="dp-dip--density-independent-pixel">dp (dip : Density Independent Pixel)</h4>
<blockquote>
<p>픽셀에 독립적인 단위로 안드로이드의 다양한 해상도를 지원하기 위해 만든 다위이다.</p>
</blockquote>
<ul>
<li>dip와 비슷해 보이지만 전혀 다른 아이다.</li>
</ul>
<hr>
<h4 id="sp">sp</h4>
<ul>
<li>sp와 비슷해보이지만 사용자가 선택한 글꼴 크기에 의해 크기가 조절된다.</li>
</ul>
<p>Layout 등 UI적인 요소는 dp단위를 사용하는 것이 좋고
글자 크기에는 sp를 사용하는 것이 좋다.</p>
<hr>
<blockquote>
<p><a href="https://re-build.tistory.com/34">해상도별 레이아웃 대응 고찰</a> 
위 글을 참고하여 해상도별 레이아웃에 대한 정리를 해보고자 한다. 
각자의 방법이 있겠지만 위 글의 방법이 좋다고 나는 생각한다.</p>
</blockquote>
<h3 id="🖐-레이아웃-세분화">🖐 레이아웃 세분화</h3>
<ul>
<li>각 기기에 대한 레이아웃 파일을 세분화하여 관리하는 방법</li>
</ul>
<p>물론 정말 기기마다 레이아웃을 만들어야 한다면 이만큼 비효율적일 수도... 사이즈도 엄청 커지고 관리도 힘들것이다. 
그래서 안드로이드에서 크기, 해상도, 방향 등으로 일반화하여 대응이 가능하도록 지원하고 있다. </p>
<p>위에서 살펴본 DPI를 떠올려보자.</p>
<p><strong>Dots Per Inch = 1인치 당 들어가있는 픽셀의 개수</strong> 기억나는가?</p>
<p>기기의 dpi가 기준 되는 dpi와 정확하게 맞아야 하는건 아니다. 
기기의 dpi와 가장 비슷한 레이아웃으로 자동으로 찾아간다.
이때 고밀도에서 저밀도 순으로 우선순위가 정해진다.</p>
<h4 id="레이아웃-세분화의-장단점">레이아웃 세분화의 장단점</h4>
<p><strong>장점</strong></p>
<ul>
<li>여러 기기 대응이 가능하다.</li>
<li>여러 기기에서 같은 비율의 이미지들과 글자를 사용하여 같은 화면처럼 표시가 가능하다.</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li>관리가 힘들다.. 유지보수/추가로 인해 레이아웃이 바뀐다면? 🤮</li>
</ul>
<h4 id="🧐-그럼-결국-어떻게-해상도별-레이아웃-대응을-할까">🧐 그럼 결국 어떻게 해상도별 레이아웃 대응을 할까?</h4>
<p>dimens.xml을 이용하는 방법
<strong>레이아웃은 하나로 통일시키고 dimes.xml을 세분화하여 사용하는 방법</strong></p>
<pre><code> &lt;ImageView

        android:layout_width=&quot;@dimen/imageWidth&quot;

        android:layout_height=&quot;@dimen/imageHeight&quot;

        android:background=&quot;@color/colorAccent&quot; /&gt;</code></pre><p><strong>dimens.xml (mdpi)</strong></p>
<pre><code>
    &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;

    &lt;resources&gt;

        &lt;dimen name=&quot;imageWidth&quot;&gt;40dp&lt;/dimen&gt;
        &lt;dimen name=&quot;imageHeight&quot;&gt;20dp&lt;/dimen&gt;
        &lt;dimen name=&quot;textSize&quot;&gt;12dp&lt;/dimen&gt;
        &lt;dimen name=&quot;topMargin&quot;&gt;5dp&lt;/dimen&gt;

   &lt;/resources&gt;</code></pre><p>dimens를 mdpi, hdpi, xhdpi, xxhdpi 별로 나눠두면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 세그멘테이션]]></title>
            <link>https://velog.io/@jaeyunn_15/OS-%EC%84%B8%EA%B7%B8%EB%A9%98%ED%85%8C%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@jaeyunn_15/OS-%EC%84%B8%EA%B7%B8%EB%A9%98%ED%85%8C%EC%9D%B4%EC%85%98</guid>
            <pubDate>Tue, 04 May 2021 03:47:03 GMT</pubDate>
            <description><![CDATA[<p>페이징은 프로세스를 물리적으로 일정한 크기로 나눠 메모리에 할당하였다.</p>
<h3 id="세그멘테이션">세그멘테이션</h3>
<ul>
<li>프로세스를 논리적 내용일 기반으로 나눠 메모리에 배치하는 것을 말한다.</li>
<li>세그먼트의 집합으로, 각 세그먼트의 크기는 일반적으로 같지 않다.</li>
<li>프로세스를 code, data, stack으로 나누는 것 역시 세그멘테이션의 모습이다. 물론 code, data, stack 각각 내부에서 더 작은 세그먼트로 나눌 수도 있다.</li>
</ul>
<h4 id="세그먼트를-메모리에-할당할-때는-페이지를-할당하는-것과-동일하다">세그먼트를 메모리에 할당할 때는 페이지를 할당하는 것과 동일하다.</h4>
<p>하지만 테이블은 조금 다른데, 세그멘테이션을 위한 테이블은 <strong>세그먼트 테이블</strong>이라고 한다.
그리고 세그먼트 테이블은 세그먼트 번호와 시작 주소, 세그먼트 크기를 엔트리로 갖는다.</p>
<p>세그먼트에서 주소 변환 역시, 페이징과 유사하다.
✋ <strong>한 가지 주의점은, 세그먼트의 크기는 일정하지 않기에 테이블에 limit정보가 주어진다.</strong>
CPU에서 해당 세그먼트의 크기를 넘어서는 주소가 들어오면 인터럽트가 발생해서 해당 프로세스를 강제 종료시킨다. 
<img src="https://images.velog.io/images/jaeyunn_15/post/ff347b6d-6e24-4a87-99fa-64a192e51dc4/image.png" alt=""></p>
<p>위 그림은 세그먼트 테이블과 프로세스가 할당된 메모리의 모습이다.
페이징 주소변환과 동일하게 d는 논리주소와 물리주소가 동일하다.
물리주소 a는 base[s] + d로 계산된다.</p>
<ul>
<li>논리주소 (2,100) -&gt; 물리주소 4400번지 (4300+100)</li>
<li>논리주소 (1,500) -&gt; 인터럽트로 인해 프로세스 강제 종료(범위 벗어남)</li>
</ul>
<h3 id="세그멘테이션에서의-보호공유">세그멘테이션에서의 보호/공유</h3>
<p><strong>페이징보다 세그멘테이션에서의 보호와 공유는 더 효율적이다.</strong>
보호에서는 세그멘테이션 역시 r,w,x 비트를 테이블에 추가하여, 세그멘테이션은 논리적으로 나누기에 해당 비트를 설정하기 매우 간단하고 안전하다.</p>
<p>페이징은 code+data,stack 영역이 있을 때 이를 일정한 크기로 나누므로 2가지 영역이 섞일 수가 있다. 그러면 비트 설정이 매우 까다로워진다.</p>
<p>공유에서도 마찬가지다.
<strong>페이징</strong>에서는 code 영역을 나눈다해도 <strong>다른 영역이 포함될 확률이 매우 높다</strong>.
하지만, <strong>세그멘테이션</strong>은 정확히 <strong>code 영역만 나누기에 더 효율적으로 공유를 수행</strong>할 수 있다. </p>
<h3 id="세그멘테이션--페이징">세그멘테이션 &amp; 페이징</h3>
<p>세그멘테이션은 페이징과 유사하고 보호와 공유에서는 더 나은 성능을 보여주지만, <strong>현재 대부분은 페이징 기법을 사용한다.</strong></p>
<p>그 이유는 세그멘테이션의 치명적 단점에 있다.</p>
<p>메모리 할당을 처음 시작할 때 다중 프로그래밍에서의 문제는 크기가 서로 다른 프로세스로 인해 여러 크기의 hole이 발생한다.
이로 인해, <strong>어느 hole에 프로세스를 할당하는 것에 대한 최적화 알고리즘이 존재하지 않고</strong>, 외부 단편화로 인해 메모리 낭비가 크다고 했었다.</p>
<p>세그멘테이션도 동일한 문제점이 발생한다.
왜냐? 세그멘테이션은 <strong>논리적인 단위로 나누기에 세그먼트의 크기가 다양하다.</strong>
이로 인해 다양한 크기의 hole이 발생하므로 같은 문제가 발생한다.</p>
<p>결론적으로 세그멘테이션은 보호/공유에서 효율적이고,
페이징은 외부 단편화 문제를 해결 할 수 있다.
그래서 2가지를 같이 사용하는 방법이 나왔고 두 장점을 합치기 위해 <strong>세그먼트를 페이징 기법으로 나누는 것이다. (Paged Segmentation)</strong></p>
<p>이 역시 단점은 있다.
<strong>세그먼트와 페이지가 동시에 존재할 수 있기에 주소 변환도 2번 해야 한다.</strong>
즉, CPU에서 세그먼트 테이블에서 주소 변환을 하고, 그 다음 페이지 테이블에서 또 주소 변환을 해야 한다..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 페이징]]></title>
            <link>https://velog.io/@jaeyunn_15/OS-%ED%8E%98%EC%9D%B4%EC%A7%95</link>
            <guid>https://velog.io/@jaeyunn_15/OS-%ED%8E%98%EC%9D%B4%EC%A7%95</guid>
            <pubDate>Tue, 04 May 2021 03:10:54 GMT</pubDate>
            <description><![CDATA[<h3 id="intro">Intro</h3>
<p>외부 단편화로 인한 메모리 낭비가 심하다.
Compaction을 사용하면 외부 단편화를 해결 할 수 있지만 오히려 이로인해 발생하는 오버헤드, 비효율적인 성능으로 사용하기 어렵다.
그래서 나온게 <strong>페이징</strong>이다.
hole을 가지고 해결하려 하지 않고 <strong>프로세스를 작은 단위로 나눠서 외부 단편화를 해결</strong>하려 한다.</p>
<h3 id="페이징">페이징</h3>
<ul>
<li>프로세스를 일정한 작은 크기로 나누고, hole 역시 같은 크기로 나눈다.</li>
<li>이러한 작은 조각들의 크기에 맞춰 메모리에 할당한다. </li>
</ul>
<p><strong>🧐 하지만, 하나의 프로세스는 연속적인 동작을 수행하는데 이를 작은 여러 조각으로 나누면 프로세스가 정상적으로 동작할까?</strong></p>
<p>다중 프로그래밍에서 살펴봤던 개념처럼 MMU를 통해 논리 주소와 물리주소를 나눠 사용하고 이를 MMU가 재배치 해주는 작업을 해준다고 하였다. 
이 역시 CPU를 속이는 행동이다. 
실제로 메모리는 전혀 연속적이지 않은데, CPU는 연속적으로 사용하고 있다는 것을 보장받으며 수행한다.</p>
<p>50byte크기의 프로세스가 있다고 하자. 페이징의 크기는 각 10byte로 나눈다.
<img src="https://images.velog.io/images/jaeyunn_15/post/36952a9f-0c53-4b76-a250-129fa2a33023/image.png" alt=""></p>
<p>위 그림과 같이 P1은 5개의 페이지로 나눌 수 있다.
이를 메인 메모리 5곳에 나눠 할당한다.
CPU는 논리 주소로 프로그램이 설정한대로 연속적인 주소값으로 명령을 내리고 이는 메모리로 가기전에 각 페이지의 실제 메모리 주소가 저장되어 있는 <strong>테이블에서 물리주소로 변경되어야 한다.</strong></p>
<p>프로세스를 나눈 조각을 <strong>page</strong>라고 하고, 메모리를 나눈 조각을 <strong>frame</strong>이라고 한다.
프로세스는 페이지의 집합이고, 메모리는 프레임의 집합이다.</p>
<p>프로세스를 정상적으로 사용하기 위해 MMU의 재배치 레지스터를 여러 개 사용하여 위의 그림처럼 각 페이지의 실제 주소로 변경해준다.</p>
<p>이러한 여러 개의 재배치 레지스터를 <strong>페이지 테이블</strong>이라 한다.</p>
<h3 id="주소-변환">주소 변환</h3>
<ul>
<li>페이징 기법을 사용하기 위해 여러 개로 흩어진 페이지에 CPU가 접근하기 위해서 페이지 테이블을 통해 주소를 변환해야 한다.</li>
</ul>
<h4 id="논리-주소">논리 주소</h4>
<p>CPU가 내는 주소는 2진수로 표현되고 이를 m비트가 있다고 가정하자.
여기서 하위 n비트는 오프셋 또는 변위라고 한다.
그리고 상위 m-n 비트는 페이지의 번호에 해당한다.
(n = d, m-n = p) 이렇게만 보면 이해가 안되니 예제로 보자.</p>
<p>페이지 번호(p)는 <strong>페이지 테이블의 인덱스 값.</strong>
p에 해당하는 테이블 내용은 메모리의 <strong>프레임 번호!</strong></p>
<ul>
<li>Page Size = 16bytes</li>
<li>Page Table : 5, 3, 2, 8 , 1, 4</li>
<li>논리 주소 50번지는 물리 주소 몇 번지 인가?</li>
</ul>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/61f7590d-d771-4a92-a962-ae7da8a975b4/image.png" alt=""></p>
<p>위 그림은 프로세스 P가 메모리에 할당된 모습이다. 
CPU가 50번지에 접근하려 한다.
그러면 페이지 테이블의 정보를 읽어오기 위해 논리주소를 p,d로 나눠야 한다.</p>
<p>d는 페이지 크기에 따라 달라지는 데, Page Size가 16byte이니까 2^4이다.
그래서 d = 4가 되므로 이진수의 뒤에서 4칸이 d이다. </p>
<pre><code>50 = 110010
p = 11
d = 0010</code></pre><p>P는 이진수로 11이고 십진수로 3이다.
즉, 페이지 테이블의 페이지 번호 3을 가리킨다.
페이지 3번에 해당하는 프레임번호는 8이므로 물리주소를 구성하는 f값은 8이 된다.</p>
<pre><code>f = 1000
d = 0010
물리주소 = 10000010</code></pre><p>최종적으로 물리주소는 f,d로 구성되어 있으므로 <strong>물리주소는 이진수로 10000010이 되고, 십진수로는 130번지가 된다.</strong>
즉, 변위는 2이므로 8번재 프레임의 시작주소는 128번지가 된다.</p>
<p>연속 메모리 할당을 하면서 외부 단편화가 발생하여 이를 해결하기 위해 페이징이 나왔다. 
<strong>하지만 페이징은 외부 단편화가 아닌 내부 단편화가 발생한다.</strong></p>
<h3 id="내부단편화">내부단편화</h3>
<ul>
<li>프로세스 크기가 페이지 크기의 배수가 아닐 경우, 마지막 페이지는 한 프레임을 다 채울 수 없다.</li>
<li>이로 인한 공간 발생은 메모리 낭비로 이어진다.</li>
</ul>
<p>예를 들어, 15byte 크기의 프로세스 P가 있다.
페이지 크기(프레임 크기)는 4byte로 P를 페이지로 나누면 <strong>4,4,4,3</strong>의 크기로 총 4개의 페이지가 만들어진다.
여기서 마지막 3byte 페이지는 프레임 크기보다 1byte 작으므로, 이 만큼 메모리 공간이 비게 된다. 
<strong>이렇게 비어진 공간은 프로세스 P에서도 쓰지 않고, 다른 프로세스에서도 쓰지 못하는 낭비되는 공간이 된다.</strong></p>
<p>내부단편화는 해결 방법이 없다. 😹
하지만 내부단편화는 외부단편화에 비해 낭비되는 메모리 공간은 매우 적다.
내부 단편화의 최대 낭비되는 크기는 <strong>page size - 1</strong>이 된다.
(외부 단편화는 최대 전체 메모리의 1/3이 낭비된다고 이전에 살펴봤다)
이는 무시할 정도로 작은 크기다.</p>
<h3 id="페이지-테이블-만들기">페이지 테이블 만들기</h3>
<ul>
<li><p>CPU 내부에 페이지 테이블을 만들 수 있다.
CPU 내부의 기억장치는 레지스터로 여러개의 레지스터로 페이지 테이블을 만드는 것.
CPU 내부에 페이지 테이블을 만들면, 장점은 <strong>주소 변환 속도가 빠르다</strong>. 하지만 단점은 CPU 내부에 사용할 수 있는 레지스터는 한정되어 있어 <strong>페이지 테이블의 크기가 매우 제한된다.</strong></p>
</li>
<li><p>페이지 테이블을 메모리 내부에 만들 수도 있다.
메모리 내부에 만드는 것의 장단점은 CPU와 정반대이다. 
즉, 장점은 <strong>페이지 테이블의 크기 제한이 없는 것</strong>이고 단점은 <strong>주소 변환 속도가 느리다는 것</strong>이다.
CPU는 프로세스의 주소에 접근하기 위해 메모리에 위치한 페이지 테이블에 한 번, 실제 주소로 접근하는데 한 번해서 메모리에 총 2번 접근해야 하므로 속도가 2배 느려진다.</p>
</li>
</ul>
<p>이 모든 것을 해결하기 위해 페이지 테이블도 캐시로 만들어 해결한다.
페이지 테이블을 별도의 칩(SRAM)으로 만들어서 CPU와 메모리 사이에 위치시킨다. 
이러한 테이블을 <strong>TLB(Translation Lock-aside Buffer)</strong> 라고 부른다.</p>
<p>👍 CPU보다 변환 속도가 느리고 메모리보다 테이블 크기는 작지만, <strong>CPU보다 테이블 크기가 크고 메모리 보다 변환 속도가 빠르다.</strong></p>
<p>TLB는 캐시와 역할이 동일하므로, 실제 전체 페이지 테이블은 메모리에 위치해 있고 테이블의 일부를 TLB에 가져와서 사용한다.
TLB에 유효한 페이지가 있을 때와 없을 때의 속도차이가 발생한다.</p>
<p>TLB 효율을 알아보기 위해 Effective Memory Access Time을 계산해보자.</p>
<ul>
<li>메모리를 읽는 시간(Tm) = 100ns</li>
<li>TLB를 읽는 시간(Tb) = 20ns</li>
<li>TLB에 유효한 페이지 엔트리가 있을 확률(hit ratio) = 80%</li>
</ul>
<p>먼저, EMAT의 정형화된 식을 보자.</p>
<p>EMAT = h(Tb + Tm) + (1-h)(Tb + Tm + Tm), h는 hit ratio</p>
<p>예제를 계산해보면 140ns가 나온다.
hit ratio는 실제로 평균 95%이상이므로 충분히 효율적으로 동작한다고 볼 수 있다.</p>
<p>실제 유효한 메모리에 접근하는 시간은 위와 같다. TLB에 유효한 페이지가 있다면 TLB를 읽는 시간과 실제 메모리를 읽는 시간만 있으면 된다. 
하지만, TLB에 유효한 페이지가 없다면 이를 다시 메모리에서 가져와야 하므로 메모리를 총 2번 읽어야 한다.</p>
<h3 id="ref">Ref</h3>
<ul>
<li><a href="http://www.kocw.net/home/search/kemView.do?kemId=978503">KOCW 운영체제 강의</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 투 포인터(Two Pointers)]]></title>
            <link>https://velog.io/@jaeyunn_15/Algorithm-%ED%88%AC-%ED%8F%AC%EC%9D%B8%ED%84%B0Two-Pointers</link>
            <guid>https://velog.io/@jaeyunn_15/Algorithm-%ED%88%AC-%ED%8F%AC%EC%9D%B8%ED%84%B0Two-Pointers</guid>
            <pubDate>Mon, 03 May 2021 03:40:36 GMT</pubDate>
            <description><![CDATA[<h4 id="✋-1차원-배열이-주어졌을-때-특정-연속된-구간의-합이-m이-되는-경우의-수를-구하려면">✋ 1차원 배열이 주어졌을 때, <strong>특정 연속된 구간</strong>의 합이 M이 되는 경우의 수를 구하려면?</h4>
<p>가장 단순하게는 2중 반복문을 돌리는 것이다. </p>
<pre><code>public class Main{
    public static void main(String[] args){
        int[] arr = {1,2,3,4,2,5,2,3,1,1,2};
        int m = 5;

        for(int i=0; i&lt;arr.length; i++){
            int sum = arr[i];

            for(int j=i+1; j&lt;10; j++){
                if(sum==m){
                    count++;
                }else if(sum&gt;m){
                    break;
                }else{
                    sum+=arr[j];
                }
            }
        }
    }
}</code></pre><p>아주 쉽게 볼수 있는 형태이다.
근데 이렇게 하면 시간복잡도가 O(N^2)이 나온다. (2중 반복문이니까)
배열의 크기가 커질 수록 느려지게 된다.</p>
<p>결국, 1차원 배열의 연속된 구간에 대해 2중 반복문을 개선하기 위해 나온 것이 투 포인터 알고리즘이다. </p>
<h3 id="투-포인터-알고리즘">투 포인터 알고리즘</h3>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/fb1e5d5d-9ac7-4682-8bfb-59ca92975715/image.png" alt="">
위와 같은 그림이 있다.</p>
<p>위의 1차원 배열에서 연속된 구간의 합이 5인 것의 경우의 수를 구해보자.</p>
<p>위의 2중 반복문과 큰 차이는 없지만, Right를 우측으로 하나씩 옮겨가면서 arr[left] + ... + arr[right]의 값이 5보다 크다면 더 이상 right를 옮기는 것은 무의미하다. right를 우측으로 옮겨봤자 마찬가지로 5보다 크기에.
그래서 이런 경우 left를 우측으로 옮긴다.</p>
<h4 id="lets-code-it">let&#39;s code it.</h4>
<pre><code>public class Main{
    public static void main(String[] args){
        int[] arr = {1, 2, 3, 4, 2, 5, 3, 1, 1, 2};
        int m = 5;

        int count = twoPointer(arr, m);
    }

    public static int twoPointer(int[] arr, int m){
        int sum =0, count =0;
        int left=0, right=0;

        while(true){
            if(sum&gt;m){
                sum -= arr[left++]; //left를 우측으로 옮기는 경우, left를 움직이면서 이전 위치에 있던 값을 합에서 빼줌.
            }else if(right==arr.length-1){
                break;
            }else{
                sum += arr[right++]; //right를 우측으로 옮기는 경우
            }

            if(sum == m) count++;
        }

        return count;
    }
}</code></pre><h4 id="lets-solve-it">let&#39;s solve it.</h4>
<p>완전 간단한 예제 문제를 풀어보자.</p>
<ul>
<li><a href="https://www.acmicpc.net/problem/2018">https://www.acmicpc.net/problem/2018</a></li>
</ul>
<pre><code>package twoPointer;

import java.util.*;
public class boj_2018 {

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for(int i=1; i&lt;=n; i++) arr[i-1] = i;

        System.out.println(twoPointers(arr, n));
    }

    public static int twoPointers(int[] arr, int n){
        int sum=0, count=1;
        int left=0, right=0;

        while(true){
            if(sum&gt;n){
                sum -= arr[left++];
            }else if(right == arr.length-1){
                break;
            }else{
                sum += arr[right++];
            }

            if(sum==n) count++;
        }

        return count;
    }

}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 수식 최대화]]></title>
            <link>https://velog.io/@jaeyunn_15/Algorithm-%EC%88%98%EC%8B%9D-%EC%B5%9C%EB%8C%80%ED%99%94</link>
            <guid>https://velog.io/@jaeyunn_15/Algorithm-%EC%88%98%EC%8B%9D-%EC%B5%9C%EB%8C%80%ED%99%94</guid>
            <pubDate>Sat, 01 May 2021 08:12:56 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h4 id="stack-2개를-이용한-문제-풀이-데이터-타입을-잘-보자">Stack 2개를 이용한 문제 풀이! (데이터 타입을 잘 보자..)</h4>
</blockquote>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/87a1d3e3-0f8a-45b4-a5c7-f0b9bcd3d518/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-05-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.12.16.png" alt=""></p>
<h3 id="문제-설명">문제 설명</h3>
<p>IT 벤처 회사를 운영하고 있는 라이언은 매년 사내 해커톤 대회를 개최하여 우승자에게 상금을 지급하고 있습니다.
이번 대회에서는 우승자에게 지급되는 상금을 이전 대회와는 다르게 다음과 같은 방식으로 결정하려고 합니다.
해커톤 대회에 참가하는 모든 참가자들에게는 숫자들과 3가지의 연산문자(+, -, <em>) 만으로 이루어진 연산 수식이 전달되며, 참가자의 미션은 전달받은 수식에 포함된 연산자의 우선순위를 자유롭게 재정의하여 만들 수 있는 가장 큰 숫자를 제출하는 것입니다.
단, 연산자의 우선순위를 새로 정의할 때, 같은 순위의 연산자는 없어야 합니다. 즉, + &gt; - &gt; * 또는 - &gt; * &gt; + 등과 같이 연산자 우선순위를 정의할 수 있으나 +,</em> &gt; - 또는 * &gt; +,-처럼 2개 이상의 연산자가 동일한 순위를 가지도록 연산자 우선순위를 정의할 수는 없습니다. 수식에 포함된 연산자가 2개라면 정의할 수 있는 연산자 우선순위 조합은 2! = 2가지이며, 연산자가 3개라면 3! = 6가지 조합이 가능합니다.
만약 계산된 결과가 음수라면 해당 숫자의 절댓값으로 변환하여 제출하며 제출한 숫자가 가장 큰 참가자를 우승자로 선정하며, 우승자가 제출한 숫자를 우승상금으로 지급하게 됩니다.</p>
<p>예를 들어, 참가자 중 네오가 아래와 같은 수식을 전달받았다고 가정합니다.</p>
<p>&quot;100-200*300-500+20&quot;</p>
<p>일반적으로 수학 및 전산학에서 약속된 연산자 우선순위에 따르면 더하기와 빼기는 서로 동등하며 곱하기는 더하기, 빼기에 비해 우선순위가 높아 * &gt; +,- 로 우선순위가 정의되어 있습니다.
대회 규칙에 따라 + &gt; - &gt; * 또는 - &gt; * &gt; + 등과 같이 연산자 우선순위를 정의할 수 있으나 +,* &gt; - 또는 * &gt; +,- 처럼 2개 이상의 연산자가 동일한 순위를 가지도록 연산자 우선순위를 정의할 수는 없습니다.
수식에 연산자가 3개 주어졌으므로 가능한 연산자 우선순위 조합은 3! = 6가지이며, 그 중 + &gt; - &gt; * 로 연산자 우선순위를 정한다면 결괏값은 22,000원이 됩니다.
반면에 * &gt; + &gt; - 로 연산자 우선순위를 정한다면 수식의 결괏값은 -60,420 이지만, 규칙에 따라 우승 시 상금은 절댓값인 60,420원이 됩니다.</p>
<p>참가자에게 주어진 연산 수식이 담긴 문자열 expression이 매개변수로 주어질 때, 우승 시 받을 수 있는 가장 큰 상금 금액을 return 하도록 solution 함수를 완성해주세요.</p>
<h3 id="제한사항">[제한사항]</h3>
<p>expression은 길이가 3 이상 100 이하인 문자열입니다.
expression은 공백문자, 괄호문자 없이 오로지 숫자와 3가지의 연산자(+, -, <em>) 만으로 이루어진 올바른 중위표기법(연산의 두 대상 사이에 연산기호를 사용하는 방식)으로 표현된 연산식입니다. 잘못된 연산식은 입력으로 주어지지 않습니다.
즉, &quot;402+-561</em>&quot;처럼 잘못된 수식은 올바른 중위표기법이 아니므로 주어지지 않습니다.
expression의 피연산자(operand)는 0 이상 999 이하의 숫자입니다.
즉, &quot;100-2145*458+12&quot;처럼 999를 초과하는 피연산자가 포함된 수식은 입력으로 주어지지 않습니다.
&quot;-56+100&quot;처럼 피연산자가 음수인 수식도 입력으로 주어지지 않습니다.
expression은 적어도 1개 이상의 연산자를 포함하고 있습니다.
연산자 우선순위를 어떻게 적용하더라도, expression의 중간 계산값과 최종 결괏값은 절댓값이 263 - 1 이하가 되도록 입력이 주어집니다.
같은 연산자끼리는 앞에 있는 것의 우선순위가 더 높습니다.</p>
<h3 id="입출력-예">입출력 예</h3>
<p>expression    &quot;100-200*300-500+20&quot;<br>result        60420</p>
<p>expression    &quot;50<em>6-3</em>2&quot;<br>result        300</p>
<h3 id="입출력-예에-대한-설명">입출력 예에 대한 설명</h3>
<h3 id="입출력-예-1">입출력 예 #1</h3>
<p><code>* &gt; + &gt; -</code>로 연산자 우선순위를 정했을 때, 가장 큰 절댓값을 얻을 수 있습니다.
연산 순서는 아래와 같습니다.
100-200<em>300-500+20
= 100-(200</em>300)-500+20
= 100-60000-(500+20)
= (100-60000)-520
= (-59900-520)
= -60420
따라서, 우승 시 받을 수 있는 상금은 |-60420| = 60420 입니다.</p>
<h3 id="입출력-예-2">입출력 예 #2</h3>
<p><code>- &gt; *</code>로 연산자 우선순위를 정했을 때, 가장 큰 절댓값을 얻을 수 있습니다.
연산 순서는 아래와 같습니다.(expression에서 + 연산자는 나타나지 않았으므로, 고려할 필요가 없습니다.)
50<em>6-3*2
= 50</em>(6-3)<em>2
= (50</em>3)<em>2
= 150</em>2
= 300
따라서, 우승 시 받을 수 있는 상금은 300 입니다.</p>
<h3 id="접근-방식">접근 방식</h3>
<p>순차적으로 접근했다.</p>
<ol>
<li>연산자들의 순열을 구해야 한다.</li>
<li>구한 순열에 따라 연산자 우선순위를 적용하여 답을 구해야한다.
처음에는 ArrayList로 하려고 했는데 값을 넣고 삭제하고 리스트 길이 고려하는 게 복잡하다는 걸 알아서 <strong>캐시 형태로 스택을 만들어서 구현하자!</strong> 했다.</li>
</ol>
<p>정리해보면,
✅ 숫자와 문자를 나눠 배열에 저장.
✅ 거꾸로 cacheStack에 삽입!
✅ cacheStack에서 하나씩 pop()하면서 연산자 우선순위에 따라 연산자를 판별하고 맞다면 resultStack에 넣은 숫자를 pop()해서 cacheStack에서 연산자 다음의 숫자를 또 pop()해서 둘을 연산하고 resultStack()으로 보낸다!
✅ 위 과정을 하고나서 다시 다른 연산자를 계산해야 하기에 resultStack을 pop()해서 cacheStack()에 다시 넣어준다!
✅ 이 과정을 연산자 우선순위에 따라 쭉~ 하면 마지막에 cacheStack에만 값이 하나 남는다.
✅ 하나 남는 값을 여러 값들과 Math.max로 비교하여 정답을 반환한다.</p>
<p><strong>핵심은 스택 2개를 왔다갔다 하면서 연산자가 있으면 pop()을 통해 값을 계산하고 넣고 빼고 하는 방식이다!</strong></p>
<h3 id="주의할-점">주의할 점!</h3>
<p>나는 처음에 구현하고 채점하니까 70.0/100.0이 나왔다...
뭐지? 싶어서 한~~참 고민해보니까</p>
<pre><code>연산자 우선순위를 어떻게 적용하더라도, expression의 중간 계산값과 최종 결괏값은 절댓값이 2^63 - 1 이하가 되도록 입력이 주어집니다.</code></pre><p>위와 같은 제한 사항이 있었다. 
그래 나의 계산 과정은 모두 int였고 결과만 long으로 반환하려는 놀부심보였다...
코드 내 계산 과정에 있는 int를 모두 long으로 교체 한 후, 통과할 수 있었다.</p>
<h3 id="코드">코드</h3>
<pre><code>import java.util.*;
class Solution {
    static String[] num, cal;
    static Stack&lt;String&gt; cacheStack = new Stack&lt;&gt;(); //계산 이전 값들 넣어둘 곳
    static Stack&lt;String&gt; resultStack = new Stack&lt;&gt;();//계산 이후 값들 넣어둘 곳
    static long answer = 0;

    public long solution(String expression) {        
        Set&lt;String&gt; set = new HashSet&lt;&gt;();

        num = expression.replaceAll(&quot;[^0-9]&quot;,&quot; &quot;).split(&quot; &quot;);
        cal = expression.replaceAll(&quot;[0-9]&quot;,&quot;&quot;).split(&quot;&quot;);        
        for(String c : cal) set.add(c);

        String[] calList = new String[set.size()]; //계산 조합을 위해 필요        
        Iterator it = set.iterator();
        int a=0;
        while(it.hasNext()) calList[a++] = (String)it.next();        

        perm(calList, calList.length, 0);        

        return answer;
    }

    public static void getMoney(String[] calList){
        //초기 설정
        for(int i=cal.length-1; i&gt;=0; i--){
            if(i==cal.length-1) cacheStack.push(num[i+1]);
            cacheStack.push(cal[i]);
            cacheStack.push(num[i]);
        }

        for(int i=0; i&lt;calList.length; i++){
            String cc = calList[i]; 

            while(!cacheStack.isEmpty()){
                String p = cacheStack.pop();

                if(p.equals(cc)){
                    long n1 = Long.parseLong(resultStack.pop());                    
                    long n2 = Long.parseLong(cacheStack.pop());
                    resultStack.push(getCalculate(p, n1, n2));
                }else{
                    resultStack.push(p);
                }

            }            

            while(!resultStack.isEmpty()){
                cacheStack.push(resultStack.pop());
            }            
        }

        while(!cacheStack.isEmpty()){                        
            answer = Math.max(answer, Math.abs(Long.parseLong(cacheStack.pop())));           
        }
    }

    public static void perm(String[] calList, int p, int r){
        if(p==r){
            getMoney(calList);
        }else{
            for(int i=0; i&lt;calList.length; i++){
                swap(calList, i, r);
                perm(calList, p, r+1);
                swap(calList, i, r);
            }
        }
    }

    public static void swap(String[] list, int i, int r){
        String tmp = list[i];
        list[i] = list[r];
        list[r] = tmp;
    }

    public static String getCalculate(String p, long n1, long n2){
        long result = 0;
        if(p.equals(&quot;+&quot;)){
            result = n1+n2;
        }else if(p.equals(&quot;-&quot;)){
            result = n1-n2;
        }else{
            result = n1*n2;
        }
        return String.valueOf(result);
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 주기억장치]]></title>
            <link>https://velog.io/@jaeyunn_15/OS-%EC%A3%BC%EA%B8%B0%EC%96%B5%EC%9E%A5%EC%B9%98</link>
            <guid>https://velog.io/@jaeyunn_15/OS-%EC%A3%BC%EA%B8%B0%EC%96%B5%EC%9E%A5%EC%B9%98</guid>
            <pubDate>Sat, 01 May 2021 05:03:54 GMT</pubDate>
            <description><![CDATA[<p><strong>OS에서 CPU자원을 관리하는 프로세스 관리 뿐 아니라 메모리 관리 역시 매우 중요한 사항이다!</strong></p>
<p>현재에도 여전히 메모리를 최대한 효율적으로 사용하기 위한 여러 방법들이 연구되고 OS 기능에서 매우 중요한 부분을 차지 한다.</p>
<blockquote>
<p>이 글은 KOCW 운영체제 강의를 토대로 작성되는 내용입니다.</p>
</blockquote>
<h3 id="1-메모리에-프로그램-할당하기">1. 메모리에 프로그램 할당하기</h3>
<p>메모리는 기본적으로 <strong>주소(Address), 데이터(Data)</strong>로 구성되어있다.</p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/6fb2985e-00ee-4929-9817-c6ea13af2852/image.png" alt=""></p>
<p>CPU와 메모리는 양방향으로 위 그림처럼 정보를 주고 받게 된다.
CPU는 주소를 가지고 메인 메모리에 요청을 하거나 해당 주소에 계산 결과를 저장하고,
메모리는 요구하는 주소에 저장되어 있는 데이터를 CPU에게 전달한다.</p>
<p>프로그램의 빌드 과정은 <strong>소스파일 ➡️ 목적 파일 ➡️ 실행 파일</strong> 순이다.</p>
<ul>
<li>소스 파일 : 고수준언어 또는 어셈블리어</li>
<li>목적 파일 : 컴파일 또는 어셈블 결과</li>
<li>실행 파일 : 링크 결과</li>
</ul>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/95fc7ea0-e797-4bc4-b18e-4cd7423604e9/image.png" alt=""></p>
<p>위 그림은 프로그램이 만들어지는 과정을 표현한 그림이다.</p>
<p><strong>1. 소스파일은 컴파일러에 의해 컴파일 수행 결과로 목적 파일을 생성한다.</strong>
프로그래밍을 하면 외부 라이브러리를 사용하는 경우가 빈번한데, 컴파일 타임에 이를 추가하지 않기에 목적 파일에는 이에 대한 정보는 없다.
<strong>2. 링크 단계에서 하드디스크에서 프로그래머가 추가한 라이브러리를 찾아 정보를 추가하여, 실행 파일을 만든다.</strong>
이 프로개름을 실행하면 로더(loader)에 의해 메인 메로리에 할당 된다.</p>
<p>그리고 생성된 프로그램은 Code, Data, Stack 영역으로 나뉜다.
단순 생성된 프로그램은 Code, Data 영역만 존재하며,
메모리에 적재되었을 때는 실제로 실행해야 하기에 stack영역이 추가된다.</p>
<h4 id="실제로-프로그램을-메모리에-올리려면-이-프로그램을-메모리의-몇-번지에-할당할까">실제로 프로그램을 메모리에 올리려면 이 프로그램을 메모리의 몇 번지에 할당할까?</h4>
<p>만약 OS가 없다면 프로그래머가 이를 직접 해줘야 한다.(고수준언어에서는 직접 주소를 다루지 않는 경우가 많다)</p>
<p>다중 프로그래밍 환경에서는 여러 프로그래밍이 메모리에 적재되고 교체 되는 과정이 있기에 한 프로그램은 고정적인 공간을 차지 할 수 없다.
위의 문제를 해결해주는 것이 바로 <strong>MMU</strong>이다. 
<strong>MMU에는 프로그램이 메모리에 할당될 때마다 다른 주소 공간을 사용하기에 재배치 레지스터가 별도로 존재한다.</strong></p>
<h3 id="mmu의-존재">MMU의 존재</h3>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/7936f0d6-4142-4d39-97a2-12e4a6838d3c/image.png" alt=""></p>
<p>위의 그림처럼 MMU가 존재함으로 인해서 프로그램은 메인 메모리에 해당 주소를 사용할 수 있는지 여부를 생각하지 않고 주소를 사용한다.</p>
<p>🙌 해당 프로그램이 사용하는 시작 주소가 0번지라고 할 때, 실제 메인 메모리에서는 할당되는 주소가 유동적이기에 0번지라는 주소를 실제 할당된 주소로 변경해줘야 한다. </p>
<p>이게 <strong>재배치 레지스터의 역할</strong>이다.
마치 필터링을 해주듯이 맵핑을 해주게 된다.</p>
<p><strong>MMU의 기능</strong>에서 보면,
이전에 메모리 보호를 위해 base, limit레지스터가 있었다.
CPU에서 주소를 사용하는데 이 주소가 해당 프로그램의 base~limit범위를 벗어나면 인터럽트를 발생시켜 프로그램을 강제 종료 시킨다.</p>
<p>base/limit 기능 이외에도 위에서 말한 reallocation 기능을 통해 프로그램이 어느 주소를 사용하더라도 실제 메인 메모리에서 할당된 주소를 찾아갈 수 있도록 <strong>address traslation</strong> 동작을 수행한다.</p>
<p><strong>⭐️ 즉, CPU는 프로그램에 설정된 주소를 계속 사용하고 메모리에 명령을 보내지만, MMU에 의해 실제로 프로그램이 할당된 메모리 주소로 변환해서 사용할 수 있는 것이다.</strong> </p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/e4f26187-9865-4abf-9046-2e3ef6c23270/image.png" alt="">
MMU에 의해 위 그림과 같이 주소는 2가지로 구분된다.
CPU에서 사용하는 주소는 <strong>논리 주소</strong>라고 하고
메모리가 사용하는 주소는 <strong>물리 주소</strong>라고 한다.</p>
<h3 id="2-메모리-낭비-방지">2. 메모리 낭비 방지</h3>
<p>OS에서 메모리 효율은 매우 중요한 부분이다.</p>
<h3 id="동적-적재dynamic--loading">동적 적재(Dynamic  Loading)</h3>
<ul>
<li>프로그램이 실행하는 데 필요한 루틴/ 데이터만 적재하는 것.</li>
</ul>
<p>오류처리 구문은 if문과 같이 오류가 발생한 순간에만 실행하면 되기에 미리 메모리에 올려두지 않고 오류가 발생한 순간 내부 코드를 실행시키면 된다. </p>
<p>데이터 역시 모든 데이터가 필요하지 않다. 배열과 클래스의 경우 필요한 부분만 메모리에 적재하고 실행 도중 필요해지면 그때 찾아서 추가적으로 메모리에 적재한다.</p>
<p>그럼 당연히 반대로 모든 루틴과 데이터를 적재하고 실행하는 것을 정적 적재(static loading)이라고 한다. </p>
<h3 id="동적-연결dynamic-linking">동적 연결(Dynamic Linking)</h3>
<p>동적 연결은 여러 프로그램에 공통으로 사용되는 라이브러리를 중복으로 메모리에 올리지 않고 하나만 올리도록 하는 것이다.</p>
<pre><code>// P1
int a = 1;
int b = 2;
printf(&quot;%d\n&quot;, a + b);

// P2
int a = 1;
int b = 2;
printf(&quot;%d\n&quot;, a * b);</code></pre><p>위의 코드처럼 p1, p2 프로세스가 있지만 둘을 실행시키면 둘은 모두 printf()를 사용하는 라이브러리를 메모리에 적재하게 된다. 이는 중복 적재이다.</p>
<p>같은 라이브러리를 메모리에 중복으로 적재하면 메모리 낭비가 발생한다.</p>
<p><strong>그렇기에 프로그램이 메모리에 적대된 후에 링크(link)작업을 수행한다.</strong>
기존에는 실행 파일이 만들어지기 전에 링크 과정을 수행하였는데, 이를 정적 연결이라고 한다.</p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/3c03e9cb-46a4-445d-a95f-d0cc59d72981/image.png" alt=""></p>
<p>공통 라이브러리(printf())를 연결한 모습이다.
리눅스에서는 이러한 라이브러리를 <strong>공유 라이브러리</strong>
윈도우에서는 <strong>동적 연결 라이브러리</strong> 라고 한다.</p>
<h3 id="swapping">Swapping</h3>
<ul>
<li>메모리에 적재되어 있는 프로세스 중 오랫동안 사용하지 않은 프로세스를 프로세스 이미지 형태로 만든 후 하드디스크에 내려보낸다. 
메모리에서 Backing Store로 가는 것을 <strong>swap-out,</strong>
다시 Backing Store에서 메모리로 가는 것을 <strong>swap-in</strong>이라고 한다.</li>
</ul>
<p>프로세스 이미지는 해당 프로그램이 메모리에 적재된 후 실행되면서 데이터를 추가하거나 변경하는 등의 과정을 거치는데, <strong>현재 데이터의 상태를 프로세스 이미지라고 부른다.</strong></p>
<p>swapping 과정으로 인한 프로세스 이미지를 저장하기 위해 하드 디스크 일부분을 분리하여 사용하는데 이를 <strong>backing store 혹은 swap device</strong>라고 부른다.</p>
<p>Backing Store의 크기는 대략 메인 메모리 크기 정도로 예상할 수 있다. 
메모리의 모든 프로세스가 쫓겨난다고 해도 메인 메모리 크기를 넘지 않기 때문이다. 
메인 메모리 크기가 크지 않는 PC나 스마트폰은 하드디스크의 일부를 backing store로 사용하지만 메모리 크기가 크다면 따로 하드디스크 자체를 backing store로 사용하는 경우도 있다. </p>
<p>Swap-out된 프로세스가 다시 swap-in될때 이전의 메모리 주소가 아닌 새로운 주소로 갈 수 있다. 이는 해당 프로세스가 backing store에 있는 동안 다른 프로세스가 해당 주소공간을 사용할 수 있기 때문이다.
<strong>하지만 이는 MMU의 재배치 레지스터로 인해 어디에 적재되어도 상관없이 정상동작이 가능하다.</strong></p>
<p>프로세스의 크기가 커지고, 하드디스크는 메인 메모리보다 속도면에서 매우 느리고 swapping 동작의 오버헤드가 매우크다.
하지만 이로 인해 얻는 이득이 더 많으므로 대부분의 운영체제는 이를 사용하고 있고, 속도가 중요한 서버 컴퓨터나 슈퍼 컴퓨터는 backing store를 하드 디스크가 아닌 좀 더 빠른 저장 자칠르 사용하기도 한다.</p>
<h3 id="연속-메모리-할당">연속 메모리 할당</h3>
<p>현재는 메모리에 여러 프로세스가 할당되는 다중 프로그래밍 환경이다.</p>
<p>부팅 직후 메모리 상태를 보면, OS만 할당되어 있고 비어 있다.
이러한 비어있는 공간을 <strong>hole</strong>이라고 부른다.</p>
<p>즉, 부팅 직후 운영체제와 big single hole이 존재한다.</p>
<p>시간이 지나면서 프로세스가 생성되고 종료하고를 반복하면, 여러 곳에 서로 다른 크기의 홀이 존재한다. 이러한 상태를 scattered holes라고 한다.</p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/07c566c4-21b6-442b-a675-1f236ad9d619/image.png" alt=""></p>
<p>부팅 직후 여러 프로세스들이 생성, 종료를 반복한 후의 상태이다.
이와 같이 hole들이 불연속하게 흩어진 상태를 <strong>메모리 단편화</strong>라고 한다.</p>
<p>메모리 단편화로 인해 여러 곳에 Hole이 흩어진 상태에서 하나의 프로세스가 메모리에 할당되려면 문제가 발생할 수 있다.</p>
<p>hole이 3개가 있고 각 크기는 50byte, 50byte, 80byte이다.
근데 할당하려는 프로세스 크기가 150byte이다. 각 홀들을 하나로 합치면 230byte로 이 프로세스를 할당할 수 있지만 실제로는 나뉘어져 있기에 할당되지 못한다. </p>
<p>이러한 현상을 <strong>외부 단편화</strong>라고 한다.</p>
<h3 id="연속-메모리-할당-방식">연속 메모리 할당 방식</h3>
<p>외부 단편화의 해결 방법을 살펴보기 전 연속 메모리 할당 방식을 먼저 보자.
연속 메모리 할당 바식에는 3가지가 있다.
<strong>First-fit, Best-fit, Worst-fit</strong></p>
<ul>
<li><p>First-fit(최초 적합) : 최초 적합은 할당할 프로세스 크기보다 크거나 같은 hole을 탐색하는 순서 중에서 가장 먼저 찾은 hole에 프로세스를 할당하는 것.</p>
</li>
<li><p>Best-fit(최적 적합) : 최적 적합은 할당할 프로세스 크기와 hole 크기의 차이가 가장 작은 hole에 프로세스를 할당하는 것. (hole크기는 프로세스 크기보다 반드시 커야한다)</p>
</li>
<li><p>Worst-fit(최악 적합) : 최적 적합과 반대로 할당할 프로세스 크기와 hole크기 차이가 가장 큰 hole에 프로세스를 할당하는 것.</p>
</li>
</ul>
<p>Hole은 100kb, 500kb, 600kb, 300kb, 200kb 총 5개가 있고
프로세스는 P1, P2, P3, P4 총 4개가 있다.
프로세스의 각 크기는 212kb, 417kb, 112kb, 426kb이다.</p>
<ul>
<li><p>First-fit
<img src="https://images.velog.io/images/jaeyunn_15/post/887240ca-d147-45cf-9778-92937e738390/image.png" alt=""></p>
</li>
<li><p>Best-fit
<img src="https://images.velog.io/images/jaeyunn_15/post/8b6aa3ae-2e34-42a4-8d85-7ef9e00a846d/image.png" alt=""></p>
</li>
<li><p>Worst-fit
<img src="https://images.velog.io/images/jaeyunn_15/post/a97f2ab2-86ba-409c-a3ab-672875f8de36/image.png" alt=""></p>
</li>
</ul>
<p>각 3가지 방식대로 프로세스를 할당하였다.</p>
<p>결과를 보면 best-fit은 4개의 프로세스를 모두 할당할 수 있고 
나머지 전략은 마지막 프로세스를 할당하지 못한다. 
모든 hole을 합치면 p4를 할당할 수 있지만 hole들은 나눠져 있기에 할당할 수 없다 = 외부 단편화.</p>
<p>각 할당 방식의 일반적인 성능 비교를 보면, 
속도면에서는 first-fit이 가장 빠르다.
메모리 이용률면에서는 first-fit, best-fit이 비슷하다.</p>
<p>하지만 여러 실험을 통해 best-fit을 사용하더라도 외부 단편화로 인해 전체 메모리의 1/3정도를 낭비한다고 한다.
거의 사용불가 수준.</p>
<h4 id="compaction">Compaction</h4>
<p>이를 해결하는 방법 중 하나는 <strong>Compaction</strong>이다.
<strong>여러 곳에 흩어진 hole들을 강제로 하나로 합치는 것이다.</strong>
하지만 hole을 옮기는 오버헤드가 너무 크고, 어느 hole을 옮겨야 빠르게 합칠 수 있는지에 대한 최적 알고리즘이 존재하지 않는 큰 단점이 있다.</p>
<h3 id="ref">Ref</h3>
<ul>
<li><a href="http://www.kocw.net/home/search/kemView.do?kemId=978503">KOCW 운영체제 양희재 교수님 강의</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 운영체제 서비스]]></title>
            <link>https://velog.io/@jaeyunn_15/OS-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EC%84%9C%EB%B9%84%EC%8A%A4</link>
            <guid>https://velog.io/@jaeyunn_15/OS-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EC%84%9C%EB%B9%84%EC%8A%A4</guid>
            <pubDate>Mon, 26 Apr 2021 14:19:38 GMT</pubDate>
            <description><![CDATA[<h4 id="운영체제의-주요-서비스">운영체제의 주요 서비스</h4>
<ul>
<li><strong>HW 자원을 각 사용자 어플리케이션에 적절히 분배해주는 것.</strong></li>
<li>HW 자원은 CPU, Main Memory, 하드디스크, 키보드, 마우스, 프린터 등이 존재한다.</li>
<li>이러한 하드웨어 자원을 사용자 어플리케이션이 요구하거나 OS내의 규칙에
의해 <strong>적절히 분배하여 컴퓨터의 성능을 최대한 효율적</strong>으로 사용해야 한다.</li>
</ul>
<h3 id="1프로세스-관리">1.프로세스 관리</h3>
<ul>
<li>운영체제 기능 중 가장 중요한 기능</li>
<li>프로세스와 프로그램은 기본적으로 구분된다.</li>
</ul>
<p><strong>프로세스</strong>는 <strong>실제 메인 메모리에서 실행 중인 프로그램.</strong>
<strong>프로그램</strong>은 <strong>하드 디스크와 같은 보조 기억장치에서 아무런 동작을 하지 않는 상태.</strong>
어떠한 요청에 의해 메인 메모리에 할당하여 CPU를 사용하면서 실행하게 되는데 이를 프로세스라고 부른다.</p>
<h4 id="프로세스-관리의-주요-기능">프로세스 관리의 주요 기능</h4>
<ul>
<li>프로세스의 생성 과 소멸</li>
<li>프로세스 활동 일시 중지, 활동 재개</li>
<li>프로세스 간 통신(IPC)</li>
<li>프로세스 간 동기화</li>
<li>교착상태 관리</li>
</ul>
<h3 id="2-주기억장치-관리">2. 주기억장치 관리</h3>
<ul>
<li>주기억장치 즉, <strong>메인 메모리는 프로그램이 실행되기 위한 공간.</strong></li>
</ul>
<p>CPU는 오직 메인 메모리에 있는 프로그램(프로세스)하고만 통신이 가능하다.
주기억장치 관리에서는 <strong>메인 메모리를 효율적으로 사용하도록 관리</strong>한다.</p>
<ul>
<li>프로세스에게 메모리 공간 할당</li>
<li>메모리의 어느 부분이 어느 프로세스에게 할당되었는지 추적 및 감시</li>
<li>프로세스 종료 시 메모리 회수</li>
<li>메모리의 효과적 사용</li>
<li>가상 메모리 : 물리적 실제 메모리보다 큰 용량을 사용할 수 있다.</li>
</ul>
<h3 id="3-파일-관리">3. 파일 관리</h3>
<p>디스크는 물리적으로 Track과 Sector로 구성되어 있으며, 여기서 <strong>파일이라는 논리적 관점으로 데이터를 바라보고 관리하는 것</strong>이다.</p>
<p>파일은 OS가 실행되는 컴퓨터에서 자주 볼 수 있는데, 이는 복잡한 과정으로 하드 디스크에 저장되어 있는 것을 사용자가 편리하게 사용할 수 있게 <strong>파일이라는 논리적인 형태로 OS에서 관리하여 보여준다.</strong></p>
<ul>
<li>파일 생성과 삭제</li>
<li>디렉토리의 생성과 삭제</li>
<li>기본 동작 지원 : open, close, read, write, create, delete</li>
<li>Track/Sector : file간 매핑</li>
<li>백업</li>
</ul>
<h3 id="4-보조기억장치-관리">4. 보조기억장치 관리</h3>
<p>하드디스크, 플래시 메모리가 있다.
하드디스크에서 아무 것도 저장되어 있지 않는 공간을 block이라 하는데, 보조기억장치 관리는 이를 관리하는 것.</p>
<ul>
<li>빈 공간 관리</li>
<li>저장공간 할당</li>
<li>디스크 스케줄링</li>
</ul>
<h3 id="5-입출력-장치-관리">5. 입출력 장치 관리</h3>
<p>키보드, 마우스, 프린터, 스피커 등</p>
<ul>
<li>장치 드라이브</li>
<li>입추력 장치 성능 향상 : buffering, caching, spooling</li>
</ul>
<h3 id="6-시스템-콜">6. 시스템 콜</h3>
<p><strong>유저 프로세스에서 운영체제 서비스를 필요로 할 때</strong> 이를 받기 위해 사용하는 호출.
<img src="https://images.velog.io/images/jaeyunn_15/post/74bcd190-1e9a-4991-ae34-39f3787f6c09/image.png" alt="">
Process1에서 프로세스 관리에 의해 System Call을 요청한 상태.
프로세스가 실행하는 중간에 운영체제 서비스가 필요하면 <strong>시스템 콜을 통해 운영체제 안의 해당 코드로 점프</strong>할 수 있다.</p>
<h4 id="주요-시스템-콜">주요 시스템 콜</h4>
<ul>
<li>Process: end, abort, load, execute, create, terminate, get/set, attributes, wait event, signal event</li>
<li>Memory : allocate, free</li>
<li>File : create, delete, open, close, read, write, get/set attributes</li>
<li>Device : request, release, read, write, get/set attributes, attach/detach devices</li>
<li>information : get/set time, get/set system data</li>
<li>Communication : socket, send, receive</li>
</ul>
<h3 id="reference">Reference</h3>
<ul>
<li><a href="https://velog.io/@codemcd/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-4.-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EC%84%9C%EB%B9%84%EC%8A%A4">운영체제-OS-운영체제 서비스</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 시스템 호출 (System. Calls)]]></title>
            <link>https://velog.io/@jaeyunn_15/OS-%EC%8B%9C%EC%8A%A4%ED%85%9C-%ED%98%B8%EC%B6%9C-System.-Calls</link>
            <guid>https://velog.io/@jaeyunn_15/OS-%EC%8B%9C%EC%8A%A4%ED%85%9C-%ED%98%B8%EC%B6%9C-System.-Calls</guid>
            <pubDate>Mon, 19 Apr 2021 07:13:38 GMT</pubDate>
            <description><![CDATA[<h3 id="시스템-콜">시스템 콜?</h3>
<ul>
<li>OS의 커널이 제공하는 서비스에 대해, 응용 프로그램의 요청에 따라 커널에 접근하기 위한 인터페이스</li>
<li>보통 C,C++과 같은 고급 언어로 작성된 프로그램들은 직접 시스템 호출을 사용할 수 없기에 고급 API를 통해 시스템 호출에 접근하게 하는 방법</li>
</ul>
<p>연관지어 나오는 내용
<strong>Q. 함수 호출과 시스템 호출은 뭐가 달라요?</strong>
-&gt; 함수 호출은 사용자가 작성한 함수 및 라이브러리의 메서드 등을 호출하는 것. 시스템 호출은 OS내에 미리 정의되어 있는 함수를 호출하는 것.</p>
<h3 id="시스템-콜의-필요-이유">시스템 콜의 필요 이유</h3>
<ul>
<li>우리가 일반적으로 사용하는 프로그램은 &#39;응용 프로그램&#39;이다.</li>
<li>유저레벨의 프로그램은 유저레벨의 함수들 만으로 많은 기능을 구현하기 힘들기에 커널의 도움을 받아야 한다. </li>
<li>이러한 작업은 응용 프로그램으로 대표되는 유저 프로세스에서 유저모드에서는 수행할 수 없다.</li>
<li>반드시 커널에 관련된 것은 커널 모드로 전환한 후에야, 해당 작업을 수행할 권한이 생긴다.</li>
<li>커널 모드를 통한 이러한 작업은 <strong>반드시 시스템 콜을 통해 수행</strong>하도록 설계되어 있다. 
<img src="https://images.velog.io/images/jaeyunn_15/post/42e12913-1d90-4b69-9515-07a0a2c621af/image.png" alt=""></li>
</ul>
<p><strong>Q. 권한이 왜 필요할까?</strong></p>
<ul>
<li>해커가 악의적으로 시스템 콜을 사용하는 경우, 초보가 의도치 않게 아무 함수를 호출해서 시스템이 망가진 경우를 막기 위해!! </li>
<li>그래서 유저 모드에서 시스템 콜을 호출할 경우 OS에서 불법적인 접근으로 인지하고 trap을 발생시킨다..</li>
</ul>
<h3 id="시스템-호출의-유형">시스템 호출의 유형</h3>
<ol>
<li>프로세서 제어</li>
<li>파일 조작</li>
<li>장치 관리</li>
<li>정보 유지</li>
<li>통신</li>
</ol>
<h3 id="시스템-호출-종류">시스템 호출 종류</h3>
<ul>
<li><p>프로세스와 관련된 시스템 호출</p>
<ul>
<li><p>프로세스 제어용</p>
<ul>
<li>exec : 자신을 수행 가능한 다른 프로세스로 대치 수행<ul>
<li>fork : 현재의 프로세스 이미지를 복사하고 child 프로세스를 만듬</li>
</ul>
</li>
<li>wait</li>
</ul>
</li>
<li><p>pipe: 파이프</p>
</li>
<li><p>signal : SW 인터럽트 또는 시그널</p>
</li>
<li><p>exit : 프로세스 종료</p>
</li>
<li><p>getuid, setuid : 사용자 및 그룹 id 접근</p>
</li>
</ul>
</li>
<li><p>표준 파일에 대한 입출력 시스템 호출</p>
<ul>
<li>open(), create(), close(), read(), write(), lseek()..</li>
</ul>
</li>
<li><p>소켓 기반 입출력 시스템 호출</p>
<ul>
<li>socket(), bind(), listen(), accept(), connect()</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 인터럽트 (Interrupt)]]></title>
            <link>https://velog.io/@jaeyunn_15/OS-%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8-Interrupt-bdjd6uqr</link>
            <guid>https://velog.io/@jaeyunn_15/OS-%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8-Interrupt-bdjd6uqr</guid>
            <pubDate>Mon, 19 Apr 2021 06:04:58 GMT</pubDate>
            <description><![CDATA[<h3 id="인터럽트-">인터럽트 !?</h3>
<p>프로그램을 실행하는 도중, <strong>예기치 않은 상황이 발생할 경우 현재 실행중인 작업을 즉시 중단하고, 발생된 상황을 우선 처리한 후 실행 중이던 작업으로 복귀하여 계속 처리</strong>하는 것.</p>
<p>인터럽트 당한 시점의 <strong>레지스터와 PC(Program Counter : 다음 번에 실행할 명령어 주소)를 PCB에 저장</strong>해두고 CPU의 제어를 인터럽트 서비스 루틴에 넘긴다.</p>
<p>지금 수행 중인 일보다 더 중요한 일(ex. 입출력, 우선 순위 연산 등)이 발생하면 그 일을 먼저 처리하고 나서 하던 일을 계속해야 한다.</p>
<p>외부/내부 인터럽트는 <strong>CPU의 하드웨어 신호에 의해 발생</strong>
소프트웨어 인터럽트는 <strong>명령어의 수행에 의해 발생</strong></p>
<h4 id="외부-인터럽트">외부 인터럽트</h4>
<ul>
<li>입출력 장치, 타이밍 장치, 전원 등 외부적인 요인으로 발생
<code>전원 이상, 기계 착오, 외부 신호, 입출력</code></li>
</ul>
<h4 id="내부-인터럽트">내부 인터럽트</h4>
<ul>
<li>Trap이라고 부르며, 잘못된 명령이나 데이터를 사용할 때 발생
<code>0으로 나누기가 발생, 오버플로우, 명령어를 잘못 사용한 경우(Exception), 디버깅시 break point</code></li>
</ul>
<h4 id="소프트웨어-인터럽트">소프트웨어 인터럽트</h4>
<ul>
<li>프로그램 처리 중 명령의 요청에 의해 발생한 것 (SVC 인터럽트)
<code>사용자가 프로그램을 실행시킬 때 발생, 소프트웨어 이용 중에 다른 프로세스를 실행 시키면 시분할 처리를 위해 자원 할당 동작이 수행된다.</code></li>
</ul>
<h3 id="인터럽트-발생-처리-과정">인터럽트 발생 처리 과정</h3>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/d9f11290-9832-4e8a-8196-e8a917f9f6b2/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-19%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.06.12.png" alt="">
사진 출처 : <a href="https://mindstation.tistory.com/164">https://mindstation.tistory.com/164</a></p>
<ol>
<li>인터럽트 요청 발생 </li>
<li>프로그램 수행 중단 <ul>
<li>현재 수행중인 명령의 수행이 완료된 시점에서 중단</li>
<li>현재의 주기억 장치 사이클이 끝나는 시점이 아님    </li>
</ul>
</li>
<li>PC에 기억되어 있는 주소를 안전한 곳에 기억시켜서 보존<ul>
<li>상태 레지스터와 PC 등을 스택에 잠시 저장한다.</li>
</ul>
</li>
<li>인터럽트 전처리 실행<ul>
<li>원인 파악</li>
<li>처리 루틴을 호출</li>
</ul>
</li>
<li>인터럽트 처리 루틴 수행<ul>
<li>프로그램의 상태를 안전한 곳에 기억시켜 보존</li>
<li>해결</li>
</ul>
</li>
<li>보존 시킨 PC의 값을 PC에, 그리고 보존시킨 프로그램의 상태를 환원시킨 프로그램의 수행을 중단되었던 곳에서부터 계속하여 수행.</li>
</ol>
<p>전반적으로 <strong>PC의 값을 안전한 곳에 기억시켜 보존하고, 원인 판단, 인터럽트 처리루틴의 수행을 개시시키는 순서</strong>로 이뤄진다.</p>
<p>근데 위 처럼 인터럽트 기능이 없다면, 컨트롤러가 특정한 일을 할 시기를 알기 위해 지속적으로 체크를 해야 한다 
이는 <strong>폴링</strong>이다.</p>
<hr>
<p>즉, 컨트롤러가 입력을 받아들이는 방법(우선순위 판별방법)에는 2가지가 있다.</p>
<ul>
<li><p><strong>폴링 방식</strong></p>
<ul>
<li>사용자가 명령어를 사용해 입력 핀의 값을 계속 읽어 변화를 알아내는 방식</li>
<li>인터럽트 요청 플래그를 차례로 비교하여 우선순위가 가장 높은 인터럽트 자원을 찾아 이에 맞는 인터럽트 서비스 루틴을 수행. (하드웨어에 비해 속도가 느리다)</li>
</ul>
</li>
<li><p><strong>인터럽트 방식</strong></p>
<ul>
<li>MCU 자체가 하드웨적으로 변화를 체크하여 변화 시에만 일정한 동작을 하는 방식<ul>
<li>daisy chain<ul>
<li>병렬 우선순위 부여</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>인터럽트 방식은 HW로 지원 받아야 하는 제약이 있지만,
폴링에 비해 신속 대응이 가능하다.
그래서 실시간 대응의 경우 = 인터럽트 방식이 필수적이다.</p>
<hr>
<h3 id="면접-질문">면접 질문</h3>
<p><strong>Q. 한컴오피스 &#39;한글&#39;을 클릭 후 빈 화면어 커서가 깜빡이고 있다. 이때 hello world를 작성하면 컴퓨터 내부에서 어떤일이 발생하는가?</strong></p>
<ul>
<li>키보드에서 사용자 입력이 들어오면 키보드 컨트롤러가 인터럽트를 발생시켜서 CPU에게 키가 입력 되었다는 사실을 알려준다. </li>
<li>CPU는 현재 수행중이던 작업의 상태를 저장하고 인터럽트 요청 처리를 위해 OS내에 정의된 키보드 인터럽트 처리 루틴을 찾아간다.</li>
<li>키보드 인터럽트 처리 루틴은 키보드로부터 입력받은 내용을 메모리의 특정 부분에 저장해서 해당 프로그램에게 키보드 입력이 들어왔음을 알리며 인터럽트 처리를 완료한다.</li>
<li>인터럽트 처리가 끝나면 인터럽트 발생 직전 상태를 복구시켜 중단된 작업을 재개한다.</li>
</ul>
<h3 id="reference">Reference</h3>
<ul>
<li><a href="https://github.com/brave-people/brave-tech-interview/blob/main/contents/os.md#%ED%95%9C%EC%BB%B4%EC%98%A4%ED%94%BC%EC%8A%A4-%ED%95%9C%EA%B8%80%EC%9D%84-%ED%81%B4%EB%A6%AD-%ED%9B%84-%EB%B9%88-%ED%99%94%EB%A9%B4%EC%96%B4-%EC%BB%A4%EC%84%9C%EA%B0%80-%EA%B9%9C%EB%B9%A1%EC%9D%B4%EA%B3%A0-%EC%9E%88%EB%8B%A4-%EC%9D%B4%EB%95%8C-hello-world%EB%A5%BC-%EC%9E%91%EC%84%B1%ED%95%98%EB%A9%B4-%EC%BB%B4%ED%93%A8%ED%84%B0-%EB%82%B4%EB%B6%80%EC%97%90%EC%84%9C-%EC%96%B4%EB%96%A4%EC%9D%BC%EC%9D%B4-%EB%B0%9C%EC%83%9D%ED%95%98%EB%8A%94%EA%B0%80">brave-tech-interview</a></li>
<li><a href="https://gyoogle.dev/blog/computer-science/operating-system/Interrupt.html">Interrupt</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 캐시 메모리(Cache Memory)]]></title>
            <link>https://velog.io/@jaeyunn_15/OS-%EC%BA%90%EC%8B%9C-%EB%A9%94%EB%AA%A8%EB%A6%ACCache-Memory</link>
            <guid>https://velog.io/@jaeyunn_15/OS-%EC%BA%90%EC%8B%9C-%EB%A9%94%EB%AA%A8%EB%A6%ACCache-Memory</guid>
            <pubDate>Mon, 19 Apr 2021 03:48:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/jaeyunn_15/post/d4e1c5d2-12da-44e5-9026-ecbfe5a3f164/image.png" alt=""></p>
<h4 id="✋-속도가-빠른-장치와-느린-장치에서-속도-차이에-따른-병목-현상을-줄이기-위한-메모리를-말한다">✋ 속도가 빠른 장치와 느린 장치에서 속도 차이에 따른 병목 현상을 줄이기 위한 메모리를 말한다.</h4>
<blockquote>
<p>ex1) CPU 코어와 메모리 사이의 병목 현상 완화
ex2) 웹 브라우저 캐시 파일은, 하드디스크와 웹페이지 사이의 병목 현상 완화</p>
</blockquote>
<p>CPU가 주기억장치에서 데이터를 읽어올 때, 자주 사용하는 데이터를 캐시 메모리에 저장한 뒤, 다음에 이용할 때 주기억장치가 아닌 캐시 메모리에서 먼저 가져오면서 속도를 향상시킨다.</p>
<p>속도라는 장점이 있지만, 용량이 적기도 하고 비용이 비싼 점이 있다.</p>
<p>CPU에는 이러한 캐시 메모리가 2~3개 정도 사용된다. (L1, L2, L3 cache memory라고 부른다)</p>
<p><img src="https://images.velog.io/images/jaeyunn_15/post/1075dcb5-bc6a-4608-a730-ee8b14354fb4/image.png" alt=""></p>
<p>속도와 크기에 따라 분류한 것으로, 일반적으로 L1 캐시부터 먼저 사용된다.
(CPU에서 가장 빠르게 접근하고 여기서 데이터를 찾지 못하면 L2로 간다.)</p>
<h4 id="듀얼-코어-프로세서의-캐시-메모리">듀얼 코어 프로세서의 캐시 메모리</h4>
<p>: 각 코어마다 독립된 L1 캐시 메모리를 가지고, 두 코어가 공유하는 L2 캐시 메모리가 내장되어 있다.</p>
<p>만약 L1 캐시가 128kb면, 64/64로 나눠 64kb에 명령어를 처리하기 직전의 명령어를 임시 저장하고, 나머지 64kb에는 실행 후 명령어를 임시 저장한다. </p>
<ul>
<li>L1 : CPU 내부에 존재 (I-Cache(Instruction Cache) + D-Cache(Data Cache)</li>
<li>L2 : CPU와 RAM 사이에 존재</li>
<li>L3 : 보통 메인 보드에 존재</li>
</ul>
<blockquote>
<p>디스크 캐시 : 주기억장치(RAM)와 보조기억장치(하드디스크) 사이에 존재하는 캐시</p>
</blockquote>
<p>CPU는 데이터를 가져오기 위해 캐시메모리 -&gt; 메모리(RAM) -&gt; 보조기억장치(HDD) 순으로 접근한다.</p>
<ul>
<li><strong>Cache hit</strong> ✅ : 캐시 메모리의 데이터를 CPU 레지스터에 복사한다.</li>
<li><strong>Cache Miss ❎, Memory hit</strong> ✅ : 메모리에서 데이터를 캐시 메모리에 복사하고 캐시 메모리의 복제된 내용을 CPU 레지스터에 복사한다.</li>
<li><strong>Cache Miss ❎, Memory Miss ❎, HDD hit</strong> ✅ : 보조 기억장치에서 필요한 데이터를 메모리에 복사한다. 메모리에 복제된 내용을 캐시 메모리에 복제한다. 캐시 메모리의 복제된 데이터를 CPU 레지스터에 복제한다. </li>
</ul>
<h3 id="캐시-메모리-작동원리">캐시 메모리 작동원리</h3>
<ul>
<li><strong>시간 지역성</strong><ul>
<li>for, while 같은 반복문에 사용하는 조건 변수처럼 한 번 참조된 데이터는 잠시 후 또 참조될 가능성이 높음</li>
</ul>
</li>
<li><strong>공간지역성</strong><ul>
<li>A[0], A[1]과 같은 연속 접근 시, 참조된 데이터 근처에 있는 데이터가 잠시 후 또 사용될 가능성이 높음.</li>
</ul>
</li>
<li><strong>순차지역성</strong><ul>
<li>분기가 발생하지 않는 한 명령어는 메모리에 저장된 순서대로 인출/실행된다.</li>
</ul>
</li>
</ul>
<p>캐시에 데이터를 저장할 때는 이러한 참조 지역성(공간)을 최대한 활용하기 위해 해당 데이터 뿐 아니라, 옆 주소의 데이터도 같이 가져와 미래에 쓰일 것을 대비한다.</p>
<p><strong>보통 명령어(Instruction)은 공간 지역성이 높고 데이터는 시간 지역성이 높다.</strong></p>
<p>CPU가 요청한 데이터가 캐시에 있으면 &#39;Cache hit&#39; 없으면 DRAM에서 가져오면 &#39;Cache Miss&#39;.</p>
<h3 id="cache-miss의-3가지-경우">Cache Miss의 3가지 경우</h3>
<ol>
<li><strong>Cold miss (Compulsory miss)</strong></li>
</ol>
<ul>
<li>해당 메모리 주소를 처음 불러서 나는 미스</li>
</ul>
<ol start="2">
<li><strong>Conflict miss</strong></li>
</ol>
<ul>
<li>캐시 메모리에 A,B데이터를 저장해야 하는데, A,B가 같은 캐시 메모리 주소에 할당되어 있어서 나는 미스.</li>
<li>아주 좋은 예시 (항상 핸드폰과 열쇠를 오른쪽 주머니에 넣고 다니는데, 잠깐 친구가 준 물건을 받느라 손에 들고 있던 핸드폰을 가방에 넣었음. 그 이후 핸드폰을 찾으려 오른쪽 주머니에서 찾는데 없는 상황)</li>
</ul>
<ol start="3">
<li><strong>Capacity miss</strong></li>
</ol>
<ul>
<li>캐시 메모리의 공간이 부족해서 나는 미스 (Conflict는 주소 할당의 문제, Capacity는 공간의 문제)</li>
</ul>
<p>캐시 크기를 키워서 문제를 해결하려하면, 캐시 접근 속도가 느려지고 파워를 많이 먹는 단점..</p>
<h3 id="구조-및-작동-방식">구조 및 작동 방식</h3>
<ul>
<li><strong>Direct Mapped Cache</strong>
<img src="https://images.velog.io/images/jaeyunn_15/post/dd22a026-b80b-4e73-a598-56d109ebff1a/image.png" alt=""><ul>
<li>가장 기본적인 구조. </li>
<li>DRAM의 여러 주소가 캐시 메모리의 한 주소에 대응되는 다대일 방식. 위의 그림에서 메모리 공간이 32개이고 캐시 메모리 공간은 8개인 상황.
ex) 00000,01000,10000,11000인 메모리 주소는 000 캐시 메모리 주소에 맵핑</li>
<li>이때 000이 &#39;인덱스 필드&#39;, 인덱스 제외한 앞의 나머지 00,01,10,11를 태그 필드라고한다.</li>
<li>이처럼 캐시메모리는 <strong>인덱스 필드 + 태그 필드 + 데이터 필드</strong>로 구성된다.</li>
<li>간단하고 빠른 장점이 있지만, Conflict Miss가 발생하는 것이 단점이다. 
위 사진처럼 같은 색깔의 데이터를 동시에 사용할 때 발생한다.</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>Fully Associative Cache</strong></p>
<ul>
<li>비어있는 캐시 메모리가 있으면, 마음대로 주소를 저장하는 방식
저장할 때는 매우 간단하지만, 찾을 때가 문제이다.</li>
<li>조건이나 규칙이 없어서 특정 캐시 Set안에 있는 모든 블럭을 한번에 찾아 원하는 데이터가 있는지 검색해야 한다.</li>
<li>CAM이라는 특수한 메모리 구조를 사용해야 하지만 매우 비싸다..</li>
</ul>
</li>
<li><p><strong>Set Associative Cahce</strong></p>
<ul>
<li>Direct + Fully 방식.</li>
<li>특정 행을 지정하고 그 행 안의 어떤 열이든 비어있을 때 저장하는 방식.</li>
<li>Direct에 비해 검색 소도는 느리지만 저장이 빠르고 Fully에 비해 느린 대신 검색이 빠른 중간형이다. </li>
</ul>
</li>
</ul>
<h3 id="reference">Reference</h3>
<ul>
<li><a href="https://gyoogle.dev/blog/computer-science/computer-architecture/%EC%BA%90%EC%8B%9C%20%EB%A9%94%EB%AA%A8%EB%A6%AC.html">캐시 메모리</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] IPC(Inter-Process Communication)]]></title>
            <link>https://velog.io/@jaeyunn_15/OS-IPCInter-Process-Communication</link>
            <guid>https://velog.io/@jaeyunn_15/OS-IPCInter-Process-Communication</guid>
            <pubDate>Sun, 18 Apr 2021 03:05:06 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/jaeyunn_15/post/973cdf77-6417-4c6d-9a2d-2f58817b2219/image.png" alt=""></p>
<ul>
<li>Process는 독립적</li>
<li>그렇기에 다른 프로세스에게 영향을 받지도 않는다.
(스레드는 프로세스 안에서 자원을 공유하기에 영향을 받는다.)</li>
</ul>
<p>이런 독립적 구조를 가진 <strong>프로세스 간 통신</strong> 상황에서 가능하도록 해주는 게 <strong>IPC</strong>이다.</p>
<p>프로세스는 커널이 제공하는 IPC 설비를 이용하여 프로세스 간 통신을 할 수 있다.</p>
<h3 id="커널이란">커널이란?</h3>
<p><strong>운영체제의 핵심적인 부분으로, 다른 모든 부분에 여러 기본적인 서비스를 제공해준다.</strong>
IPC 설비 종류도 여러가지가 있다. 필요에 따라 IPC 설비를 선택해서 사용해야 한다.</p>
<h3 id="ipc-종류">IPC 종류</h3>
<p><strong>1. 익명 PIPE</strong></p>
<ul>
<li>파이프는 두 개의 프로세스를 연결하는데 하나의 프로세스는 데이터를 쓰기만 하고, 다른 하나는 데이터를 읽기만 할 수 있다.</li>
<li>한 쪽 방향으로만 통신이 가능한 <strong>반이중 통신</strong>이라고도 부른다.
따라서 양쪽으로 모두 송/수신을 하고 싶다면 2개의 파이프를 만들어야 한다.</li>
<li><strong>매우 간단하게 사용 할 수 있는 장점</strong>이 있고, <strong>단순한 데이터 흐름</strong>을 가질 땐 파이프를 사용하는 것이 효율적이다.</li>
<li><strong>단점으로는 전이중 통신을 위해 2개를 만들어야 할 때는 구현이 복잡</strong>해지게 된다.</li>
</ul>
<p><strong>2. Named PIPE(FIFO)</strong></p>
<ul>
<li>익명 파이프로 <strong>통신할 프로세스를 명확히 알 수 없는 경우에 사용</strong>(부모-자식 프로세스 간 통신처럼)</li>
<li>Named 파이프는 <strong>전혀 모르는 상태의 프로세스 들 사이 통신</strong>에 사용된다.</li>
<li><strong>익명 파이프의 확장된 상태</strong>로 부모 프로세스와 무관한 다른 프로세스도 통신이 가능한 것 (통신을 위해 이름 있는 파일을 사용한다.)</li>
<li>하지만, <strong>Named 파이프 역시 읽기/쓰기 동시에 불가</strong>하다. 따라서 전이중 통신을 위해서는 익명 파이프처럼 2개를 만들어야 가능하다.</li>
</ul>
<p><strong>3. Message Queue</strong></p>
<ul>
<li>입출력 방식은 Named 파이프와 동일</li>
<li>다른 점은 메시지 큐는 <strong>파이프처럼 데이터의 흐름이 아니라 메모리 공간이다.</strong></li>
<li>사용할 데이터에 번호를 붙이면서 여러 프로세스가 동시에 데이터를 다룰 수 있다.</li>
</ul>
<p><strong>4. 공유 메모리</strong></p>
<ul>
<li>파이프, 메시지 큐가 통신을 이용한 설비라면, 공유 메모리는 <strong>데이터 자체를 공유하도록 지원하는 설비</strong></li>
<li>프로세스의 메모리 영역은 독립적으로 가지며 다른 프로세스가 접근하지 못하도록 반드시 보호되어야 한다. 하지만 다른 프로세스가 데이터를 사용하도록 해야하는 상황도 필요할 것이다. 파이프를 이용해 통신을 통해 데이터 전달도 가능.
하지만, 스레드 처럼 메모리를 공유하도록 해준다면 훨씬 편할 것이다.</li>
<li>공유 메모리는 <strong>프로세스 간 메모리 영역을 공유해서 사용할 수 있도록 허용해준다.</strong></li>
<li>프로세스가 공유 메모리 할당을 커널에 요청하면, 커널은 해당 프로세스에 메모리 공간을 할당해주고 이후 모든 프로세스는 해당 메모리 영역에 접근할 수 있게된다.</li>
<li><strong>중개자 없이 곧바로 메모리에 접근할 수 있어서 IPC중 가장 빠르게 동작한다.</strong></li>
</ul>
<p><strong>5. 메모리 맵</strong></p>
<ul>
<li>공유 메모리처럼 메모리를 공유해준다.</li>
<li>메모리 맵은 열린 파일을 메모리에 맵핑시켜서 공유하는 방식이다. (즉, 공유 매개체가 파일+메모리)</li>
<li>주로 파일로 대용량 데이터를 공유해야 할 때 사용한다.</li>
</ul>
<p><strong>6. 소켓</strong></p>
<ul>
<li>네트워크 소켓 통신을 통해 데이터를 공유한다.</li>
<li>클라이언트와 서버가 소켓을 통해 통신하는 구조로, 원격에서 프로세스 간 데이터를 공유할 때 사용한다. 
서버 (bind, listen, accept) 클라이언트(connect)</li>
</ul>
<p>이러한 IPC 통신에서 프로세스 간 데이터를 동기화하고 보호하기위해 세마포어와 뮤텍스를 사용한다. 
(공유된 자언에 한번에 하나의 프로세스만 접근 시킬때)</p>
<h3 id="reference">Reference</h3>
<ul>
<li>위 글의 원본은 <a href="https://gyoogle.dev/blog/computer-science/operating-system/IPC.html">여기</a>에 있습니다. </li>
</ul>
]]></description>
        </item>
    </channel>
</rss>