<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>lee_choonghee.log</title>
        <link>https://velog.io/</link>
        <description>팔로우 기능 생기면 팔로우 당하고 싶다</description>
        <lastBuildDate>Sat, 16 Oct 2021 13:15:11 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. lee_choonghee.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/lee_choonghee" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Java] IDE 없이 개발하기]]></title>
            <link>https://velog.io/@lee_choonghee/Java-IDE-%EC%97%86%EC%9D%B4-%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@lee_choonghee/Java-IDE-%EC%97%86%EC%9D%B4-%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 16 Oct 2021 13:15:11 GMT</pubDate>
            <description><![CDATA[<h1 id="발단">발단</h1>
<p>유튜브에서 그냥 킹오브 98이나 보려고 들어갔다가 <a href="https://youtu.be/9-yrUW2gO7w">다음과 같은 영상</a>이 메인에 보였다. 꼴에 프랑스어를 조금 배우고 프로그래밍도 조금 배웠다고 유튜브 알고리즘이 띄워주나 보다. 보다보니 뭔가 IDE와 빌드툴의 도움만 받으면서 근본도 모르고 개발을 한 것 같아 영상의 내용을 글로 옮겨본다. 모하메드 교수님이 불어로 쏼라쏼라 하지만 코드는 만국 공통이니 못 알아 들을 것도 없었다. 시작해 보자!</p>
<h1 id="프로젝트-생성">프로젝트 생성</h1>
<pre><code class="language-text">1. mkdir example &amp;&amp; cd example
2. mkdir -p src/main/java
3. mkdir -p src/test/java
4. mkdir -p src/main/resources
5. mkdir -p target/classes
6. mkdir lib</code></pre>
<p>mkdir의 <code>-p</code> 옵션은 바로 필요한 디렉터리를 한 번에 만들겠다는 뜻 이다.</p>
<ol>
<li>프로젝트 폴더를 만들고 안으로 이동한다.</li>
<li>소스 코드를 작성하는 <code>main</code> 폴더를 만든다.</li>
<li>테스트 코드를 작성하는 <code>test</code> 폴더를 만든다.</li>
<li>설정 파일, 리소스 파일들을 담아두는 <code>resources</code> 폴더를 만든다.</li>
<li>컴파일 이후 <code>.class</code> 파일들을 저장할 곳을 만든다.</li>
<li>서드파티 라이브러리 <code>.jar</code> 파일들을 저장하는 곳을 만든다.</li>
</ol>
<p><code>tree</code> 명령어를 사용해서 다음과 같은 구조가 보이면 된다. </p>
<pre><code class="language-text">.
├── lib
├── src
│   ├── main
│   │   ├── java
│   │   └── resources
│   └── test
│       └── java
└── target
    └── classes</code></pre>
<blockquote>
<p>💡 맥 OS에는 tree 명령어가 없다.</p>
</blockquote>
<pre><code>brew install tree</code></pre><h1 id="소스-코드-작성">소스 코드 작성</h1>
<pre><code class="language-text">1. cd src/main/java
2. mkdir -p com/example/app &amp;&amp; cd com/example/app
3. vi App.java</code></pre>
<ol>
<li>소스 코드 작성을 위해 java 폴더로 이동한다.</li>
<li>패키지를 만들고 경로를 이동한다.</li>
<li><code>App.java</code> 라는 이름의 파일로 vim 에디터를 연다.</li>
</ol>
<p>그리고 다음과 같이 아주 간단히 <a href="https://velog.io/@lee_choonghee/Java-main-%EB%A9%94%EC%86%8C%EB%93%9C-%EB%BD%80%EA%B0%9C%EA%B8%B0">main 메소드</a>를 포함하는 자바 코드를 작성해본다. 이후에 다른 클래스를 import 해볼 것이니 걱정하지 말자!</p>
<pre><code class="language-java">package com.example.app;

public class App {
  public static void main(String[] args) {
    System.out.println(&quot;Hello World&quot;);
  } 
}</code></pre>
<h1 id="컴파일">컴파일</h1>
<p>프로젝트의 루트 경로로 돌아간 후 아래의 명령어를 실핸한다.</p>
<pre><code class="language-text">javac src/main/java/com/example/app/App.java -d target/classes</code></pre>
<p><code>App.java</code> 파일을 컴파일하고 결과를 <code>target/classes</code> 디렉토리에 넣는다는 뜻이다.</p>
<p>tree 명령어를 실행해보면 다음과 같다.</p>
<pre><code class="language-text">.
├── lib
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── app
│   │   │               └── App.java
│   │   └── resources
│   └── test
│       └── java
└── target
    └── classes
        └── com
            └── example
                └── app
                    └── App.class</code></pre>
<p>자, 이제 실행해보자!</p>
<h1 id="실행">실행</h1>
<pre><code class="language-text">java -cp target/classes com.example.app.App</code></pre>
<p><code>-cp</code> 는 클래스 패스를 설정하는 옵션이다. <code>App.class</code> 파일을 실행한다.</p>
<p>결과는 예상대로 다음과 같다.</p>
<pre><code class="language-text">Hello World</code></pre>
<p>클래스 패스를 매번 지정해 주어야하는게 조금 귀찮다. <code>java com.example.app.App</code> 을 실행하면 다음과 같이 클래스를 찾을 수 없다고 오류가 나타난다.</p>
<pre><code class="language-text">Error: Could not find or load main class com.example.app.App
Caused by: java.lang.ClassNotFoundException: com.example.app.App</code></pre>
<p>클래스 패스 설정 없이 바로 자바 프로그램을 실행하고 한다면 다음과 같이 환경 변수에 클래스 패스를 지정해주어야 한다.</p>
<pre><code>export CLASSPATH=&quot;/[YOUR_PATH_HERE]/example/target/classes:$CLASSPATH&quot;</code></pre><p>그리고 나서 <code>java com.example.app.App</code> 을 실행하면 _&quot;Hello World&quot;_가 똑같이 나타날 것이다.</p>
<h1 id="import-할-클래스-작성">import 할 클래스 작성</h1>
<pre><code class="language-text">1. mkdir src/main/java/com/example/app/service &amp;&amp; cd src/main/java/com/example/app/service
2. vi Service.java</code></pre>
<ol>
<li><code>service</code> 패키지를 추가하고 해당 경로로 이동한다.</li>
<li><code>Service.java</code> 이름의 파일을 에디터로 연다. 아래의 내용을 작성한다.</li>
</ol>
<pre><code class="language-java">package com.example.app.service;

public class Service {
    public double compute(double a, double b) {
        return a + b;
    }
}</code></pre>
<h1 id="service-컴파일">Service 컴파일</h1>
<p>프로젝트의 루트로 경로를 다시 이동시키고 아래의 명령어를 실행시킨다.</p>
<pre><code class="language-text">javac -d ./target/classes ./src/main/java/com/example/app/service/Service.java</code></pre>
<p>tree 명령어를 실행해보면 다음과 같다.</p>
<pre><code class="language-text">.
├── lib
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── app
│   │   │               ├── App.java
│   │   │               └── service
│   │   │                   └── Service.java
│   │   └── resources
│   └── test
│       └── java
└── target
    └── classes
        └── com
            └── example
                └── app
                    ├── App.class
                    └── service
                        └── Service.class</code></pre>
<p><code>Service.class</code> 파일이 생긴 것을 확인할 수 있다.</p>
<h1 id="app에-service-임포트-시키기">App에 Service 임포트 시키기</h1>
<p><code>App.java</code> 파일을 다음과 같이 수정한다. 코드 설명은 따로 하지 않아도 알 것이다.</p>
<pre><code class="language-java">package com.example.app;

import com.example.app.service.Service;

public class App {
  public static void main(String[] args) {
    if(args.length != 2) {
        System.out.println(&quot;두 개의 인수를 주세요!&quot;);
        System.exit(0);
      }
      Service service = new Service();
      double a = Double.parseDouble(args[0]);
      double b = Double.parseDouble(args[1]);
      double result = service.compute(a, b);
      System.out.println(String.format(&quot;%s 더하기 %s 는 %s 이다.&quot;, a, b, result));
  } 
}</code></pre>
<p>다시 <code>App.java</code> 파일을 컴파일 해본다. </p>
<pre><code class="language-text">javac -d ./target/classes ./src/main/java/com/example/app/App.java</code></pre>
<h1 id="app-실행하기">App 실행하기</h1>
<p>앱을 실행해본다.</p>
<pre><code class="language-text">java com.example.app.App</code></pre>
<p>결과는 다음과 같다.</p>
<pre><code>두 개의 인수를 주세요!</code></pre><p>두 개의 인수를 주고 다시 실행해본다.</p>
<pre><code class="language-text">java com.example.app.App 5 7</code></pre>
<p>결과는 다음과 같다.</p>
<pre><code class="language-text">5.0 더하기 10.0 는 15.0 이다.</code></pre>
<p>필요한 import 하고 컴파일하고 실행까지 해보았다!</p>
<h1 id="필요한-jar-파일-다운-받기">필요한 jar 파일 다운 받기</h1>
<p>테스트 코드 작성 및 실행에 필요한 jar 파일들을 다운받는다.</p>
<ul>
<li><a href="https://mvnrepository.com/artifact/junit/junit/4.13">junit-4.13.jar</a></li>
<li><a href="https://mvnrepository.com/artifact/org.hamcrest/hamcrest-core/1.3">hamcrest-core-1.3.jar</a></li>
</ul>
<p>다운로드 받은 후 <code>lib</code> 경로에 넣어준다.</p>
<h1 id="테스트-코드-작성">테스트 코드 작성</h1>
<p><code>src/test/java</code> 경로에 똑같은 <code>com/example/app/service</code> 패키지를 만들고 <code>ServiceTest.java</code> 파일을 생성하여 테스트할 코드를 작성한다. 일부러 실패하는 테스트로 만들었다.</p>
<pre><code class="language-java">package com.example.app.service;

import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class ServiceTest {
  @Test
  public void testCompute() {
    Service service = new Service();
    double a = 12;
    double b = 8;
    double expected = 100;
    double result = service.compute(a, b);
    assertEquals(result, expected, 0.001);
  }
}</code></pre>
<h1 id="테스트-코드-컴파일">테스트 코드 컴파일</h1>
<p>jar 파일과 직접 컴파일한 클래스를 불러올 수 있도록 클래스패스를 설정하여 <code>ServiceTest.java</code> 를 컴파일 한다.</p>
<pre><code class="language-text">javac -d ./target/classes -cp ./lib/junit-4.13.jar:./lib/hamcrest-core-1.3.jar:./target/classes ./src/test/java/com/example/app/service/ServiceTest.java</code></pre>
<p>tree 명령어를 실행해보면 다음과 같다.</p>
<pre><code class="language-text">.
├── lib
│   └── junit-4.13.jar
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── app
│   │   │               ├── App.java
│   │   │               └── service
│   │   │                   └── Service.java
│   │   └── resources
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── app
│                       └── service
│                           └── ServiceTest.java
└── target
    └── classes
        └── com
            └── example
                └── app
                    ├── App.class
                    └── service
                        ├── Service.class
                        └── ServiceTest.class</code></pre>
<h1 id="테스트-코드-실행">테스트 코드 실행</h1>
<p>JUnit 4의 테스트를 실행하기 위해 <a href="https://junit.org/junit4/javadoc/4.13/org/junit/runner/JUnitCore.html">JUnitCore</a> 가 필요하다. 해당 문서에 커맨드 라인에서의 실행법이 나와있다.</p>
<blockquote>
<p>To run tests from the command line, run <strong><em>java org.junit.runner.JUnitCore TestClass1 TestClass2</em></strong></p>
</blockquote>
<p>다시 한 번 클래스 패스를 설정해 필요한 클래스들을 불러오고 <code>JUnitCore</code> 로 테스트를 실행해 본다.</p>
<pre><code class="language-text">java -cp &quot;./target/classes/:./lib/junit-4.13.jar:./lib/hamcrest-core-1.3.jar:&quot; org.junit.runner.JUnitCore com.example.app.service.ServiceTest</code></pre>
<p>결과는 다음과 같다.</p>
<pre><code class="language-text">JUnit version 4.13
.E
Time: 0.006
There was 1 failure:
1) testCompute(com.example.app.service.ServiceTest)
java.lang.AssertionError: expected:&lt;20.0&gt; but was:&lt;100.0&gt;
        at org.junit.Assert.fail(Assert.java:89)
        at org.junit.Assert.failNotEquals(Assert.java:835)
        at org.junit.Assert.assertEquals(Assert.java:555)
        at org.junit.Assert.assertEquals(Assert.java:685)
        at com.example.app.service.ServiceTest.testCompute(ServiceTest.java:14)

FAILURES!!!
Tests run: 1,  Failures: 1</code></pre>
<p>잘 동작한다 😙. </p>
<h1 id="jar-파일-만들기">jar 파일 만들기</h1>
<p>jar 파일로 만들어 앱을 실행시켜 보자. 경로를 <code>target/classes</code> 를 이동시켜 <code>target</code> 경로에 <code>app.jar</code> 파일을 만든다.</p>
<pre><code class="language-text">jar cfv ../app.jar .</code></pre>
<p>옵션의 의미는 다음과 같다.</p>
<ul>
<li><code>c</code> : 자바 아카이브 파일을 생성한다.</li>
<li><code>f</code> : 파일 이름을 정한다.</li>
<li><code>v</code> : 콘솔에 진행상황을 출력한다.</li>
</ul>
<pre><code class="language-text">added manifest
adding: com/(in = 0) (out= 0)(stored 0%)
adding: com/example/(in = 0) (out= 0)(stored 0%)
adding: com/example/app/(in = 0) (out= 0)(stored 0%)
adding: com/example/app/App.class(in = 925) (out= 605)(deflated 34%)
adding: com/example/app/service/(in = 0) (out= 0)(stored 0%)
adding: com/example/app/service/Service.class(in = 272) (out= 210)(deflated 22%)
adding: com/example/app/service/ServiceTest.class(in = 559) (out= 393)(deflated 29%)</code></pre>
<p>다음과 같은 정보가 나오며 <code>app.jar</code> 이 생성되었다.</p>
<h1 id="jar-파일-실행하기">jar 파일 실행하기</h1>
<p><code>target</code> 경로에 jar 파일을 생성했으므로 해당 경로로 이동하고 다음의 명령어를 입력해 앱을 실행해 본다.</p>
<pre><code class="language-text">java -cp app.jar com.example.app.App 10 2</code></pre>
<p>결과는 다음과 같다.</p>
<pre><code class="language-text">10.0 더하기 2.0 는 12.0 이다.</code></pre>
<h1 id="manifest-추가-후-실행">Manifest 추가 후 실행</h1>
<p><code>resources</code> 폴더에 <code>MANIFEST.TXT</code> 파일을 만들고 다음 내용을 추가한다.</p>
<pre><code class="language-text">Main-Class: com.example.app.App

</code></pre>
<blockquote>
<p>💡 <strong>줄바꿈을 통해 마지막 빈 줄을 만드는 것이 매우 중요하다!!!!</strong></p>
</blockquote>
<p><code>target/classes</code> 경로로 이동한 후 Manifest 파일을 <code>app.jar</code> 생성 시 추가시켜준다 (Manifest 파일 경로를 명시해주지 않으면 디폴트로 알아서 하나 만들어 준다). </p>
<pre><code class="language-text">jar cfvm ../app.jar ../../src/main/resources/MANIFEST.TXT .</code></pre>
<p><code>target</code> 으로 이동해 앱을 실행시켜 본다.</p>
<pre><code class="language-text">java -jar app.jar 20 30</code></pre>
<p>결과는 다음과 같다.</p>
<pre><code class="language-text">20.0 더하기 30.0은 50.0 이다.</code></pre>
<h1 id="소감">소감</h1>
<p>한 번 알아본 것으로 족하고 IDE와 빌드툴에 의존해야 겠다 🤪.</p>
<h1 id="참고-자료">참고 자료</h1>
<ul>
<li><a href="https://youtu.be/9-yrUW2gO7w">Youtube - Sources de l&#39;Informaticien avec Pr.Mohamed YOUSSFI - Part 1 - Bases et Outils de Développement JAVA - Java sans IDE et sans Maven</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[FX] 외환 거래 용어 사전]]></title>
            <link>https://velog.io/@lee_choonghee/FX-%EC%99%B8%ED%99%98-%EA%B1%B0%EB%9E%98-%EC%9A%A9%EC%96%B4-%EC%82%AC%EC%A0%84</link>
            <guid>https://velog.io/@lee_choonghee/FX-%EC%99%B8%ED%99%98-%EA%B1%B0%EB%9E%98-%EC%9A%A9%EC%96%B4-%EC%82%AC%EC%A0%84</guid>
            <pubDate>Tue, 05 Oct 2021 01:47:07 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.babypips.com/">Babypips</a> 를 보고 외환 거래 용어들을 정리해 본다. 서툴러서 설명이 이상할 수 있으니 댓글로 많은 피드백 바란다! 계속 업데이트 할 예정이다. 몇 달이 걸릴지는 모르겠다... </p>
<ul>
<li>ABC 순서 입니다.</li>
<li>지금 적혀있는 내용도 변경 될 수 있습니다.</li>
</ul>
<hr>
<h2 id="ask--offer-price">Ask / Offer Price</h2>
<p>브로커가 Quote Currency 와 교환하여 Base Currency 를 판매하려는 가격이다. 만약 어떤 통화를 사고 싶다면, 브로커는 ask 가격에 판매해 줄 것이다.</p>
<hr>
<h2 id="base-currency">Base Currency</h2>
<p><code>GBP/USD</code> 와 같은 페어에서 앞에 있는 통화를 의미한다. 해당 페어에서 환율을 이야기할 때 항상 <strong>1</strong>이 된다. <strong>Base Currency 의 가치가 오를 것 같으면 구매하고 반대라면 팔면된다.</strong></p>
<hr>
<h2 id="bid">Bid</h2>
<p>브로커가 Quote Currency 와 교환하여 Base Currency 를 구매하려는 가격이다. 만약 어떤 통화를 팔고 싶다면, 브로커는 bid 가격에 구매를 해줄 것이다.</p>
<hr>
<h2 id="briics">BRIICS</h2>
<p>Brazil, Russia, India, Indonesia, China, South Africa를 줄여서 부르는 말.</p>
<table>
<thead>
<tr>
<th align="center">국가</th>
<th align="center">통화명</th>
<th align="center">ISO 코드</th>
</tr>
</thead>
<tbody><tr>
<td align="center">브라질</td>
<td align="center">헤알(real)</td>
<td align="center">BRL</td>
</tr>
<tr>
<td align="center">러시아</td>
<td align="center">루블(ruble)</td>
<td align="center">RUB</td>
</tr>
<tr>
<td align="center">인도</td>
<td align="center">루피(rupee)</td>
<td align="center">INR</td>
</tr>
<tr>
<td align="center">인도네시아</td>
<td align="center">루피아(rupiah)</td>
<td align="center">IDR</td>
</tr>
<tr>
<td align="center">중국</td>
<td align="center">위안(yuan)</td>
<td align="center">CNY</td>
</tr>
<tr>
<td align="center">남아프리카 공화국</td>
<td align="center">랜드(rand)</td>
<td align="center">ZAR</td>
</tr>
</tbody></table>
<hr>
<h2 id="brokers--trading-providers">Brokers / Trading Providers</h2>
<p>엄밀히 말하면, 중간에서 구매자와 판매자를 연결해주는 기관이 아니다. 내가 구매를 하면 브로커는 판매자가 되고, 내가 판매를 하면 브로커는 구매자가 된다.</p>
<hr>
<h2 id="buy">Buy</h2>
<p>통화를 산다는 것은 사실 Base Currency 를 사고 Quote Currency 를 파는 것을 의미한다. <em>Ask</em> 가격에 Base Currency 를 산다.</p>
<hr>
<h2 id="cee-currencies">CEE Currencies</h2>
<p>중앙 유럽과 동유럽을 합쳐서 CEE, Central and Eastern Europe, 라고 부른다. CEE 통화 중 4개의 통화가 많이 알려져있다.</p>
<table>
<thead>
<tr>
<th align="center">국가</th>
<th align="center">통화명</th>
<th align="center">ISO 코드</th>
</tr>
</thead>
<tbody><tr>
<td align="center">헝가리</td>
<td align="center">포린트(porint)</td>
<td align="center">HUF</td>
</tr>
<tr>
<td align="center">체코</td>
<td align="center">코루나(koruna)</td>
<td align="center">CZK</td>
</tr>
<tr>
<td align="center">폴란드</td>
<td align="center">즈워티(zloty)</td>
<td align="center">PLN</td>
</tr>
<tr>
<td align="center">루마니아</td>
<td align="center">레우(leu)</td>
<td align="center">RON</td>
</tr>
</tbody></table>
<hr>
<h2 id="cfd--contract-for-difference-차액-거래">CFD / Contract For Difference (차액 거래)</h2>
<p>약정 개시 시점과 종료 시점의 차액을 거래하는 상품. 약정 만료일은 단기로 끝나거나 장기로 계속 이어갈 수 있다. 수익, 손실 여부의 방향을 올바르게 예측하여 수익을 낼 수 있다.</p>
<hr>
<h2 id="close-out--offsetting--liqudating">Close Out / Offsetting / Liqudating</h2>
<p><em>Retail Forex</em> 거래에서 브로커와 반대되는 거래를 하는 행위. 트레이더가 미국 달러로 영국 파운드를 구매했다면, 영국 파운드를 미국 달러로 파는 행위를 &quot;close out&quot; 했다고 한다.</p>
<hr>
<h2 id="commodity-currencies">Commodity Currencies</h2>
<p>일부 트레이더들은 USD, EUR, JPY, GBP, CHF 만을 주요 통화로 생각한다. 그들은 AUD, NZD, CAD를 <em>commodity currencies</em> 라고 부른다.</p>
<hr>
<h2 id="counter--quote-currency">Counter / Quote Currency</h2>
<p>GBP/USD 와 같은 페어에서 뒤에 있는 통화를 의미한다. 하나의 Base Currency 를 사기 위해 Quote Currency 를 얼마나 지불해야하는지 알려주는 것이 바로 <strong>환율</strong>이다. 반대로 하나의 Base Currency 를 팔면 얼마나 Quote Currency 를 받을 수 있는지 의미한다.</p>
<hr>
<h2 id="derivative-파생-상품">Derivative (파생 상품)</h2>
<p>파생 상품은 실제 자산 보유하지 않아도 거래할 수 있도록 설계된 금융 상품이다. 예로는 옵션, 선물, 스왑 등이 있다.</p>
<hr>
<h2 id="dollars-nicknames">Dollar&#39;s nicknames</h2>
<p>buck, greenbacks, bones, benjis, benjamins, cheddar, paper, loot, scrilla, cheese, bread, moolah, dead presidents, cash money</p>
<hr>
<h2 id="etf-통화-etf">ETF (통화 ETF)</h2>
<p>세계 기축통화인 미국 달러화를 상품으로 달러화의 선물지수를 추종하도록 설계된 ETF를 통화 ETF라고 한다. 즉, 미래의 통화 가치를 대표하는 미 달러화의 환율이 상승할지 하락할지에 투자의 기준을 두고 투자하는 상품이다.</p>
<p>특징은 다음과 같다.</p>
<ul>
<li>포트폴리오가 다양화 된다.</li>
<li>개별적인 거래를 일일이 해야하는 부담을 줄일 수 있다.</li>
<li>통화 리스크에 대해 헤지를 할 수 있다.</li>
<li>펀드를 구성하는 금융, 투자 회사에 의해 만들어진다.</li>
<li>주식 상품 처럼 share를 제공한다.</li>
<li>24시간 열려있는 시장이 아니다.</li>
</ul>
<hr>
<h2 id="exchange-rate-환율">Exchange Rate (환율)</h2>
<p>서로 다른 국가간의 화폐의 상대적인 가격이다. 자기 나라 돈과 다른 나라 돈의 교환 비율.</p>
<hr>
<h2 id="exotic-currency-pairs">Exotic Currency Pairs</h2>
<p>하나의 주요 통화와 브라질(BRL), 멕시코(MXN), 칠레(CLP), 홍콩(HKD) 등과 같은 신흥 경제 국가의 화폐를 합친 통화 페어. 지정학적, 경제적인 이벤트에 매우 민감하다.</p>
<hr>
<h2 id="flat--square">Flat / Square</h2>
<p>열린 포지션이 하나도 없으면 <strong>&quot;flat&quot;</strong> 또는 <strong>&quot;square&quot;</strong> 되었다고 부른다. <strong>포지션을 닫는 것을 &quot;squaring up&quot; 이라고 부른다.</strong></p>
<hr>
<h2 id="futures-선물-거래">Futures (선물 거래)</h2>
<p>특정 자산을 미래 날짜에 지정된 가격으로 사거나 파는 계약. 통화의 경우, 하나의 화폐를 어느 날짜에 구매하거나 팔 가격을 정하는 계약이다. </p>
<hr>
<h2 id="fx--forex--foreign-exchange-market-외환-시장">FX / Forex / Foreign Exchange Market (외환 시장)</h2>
<p>통화를 거래할 수 있는 글로벌 금융시장이다.</p>
<hr>
<h2 id="g10-currencies">G10 Currencies</h2>
<p>G10 이라고 부르는 국가들의 통화. 세계에서 유동성이 가장 큰 10가지 화폐이다.</p>
<table>
<thead>
<tr>
<th align="center">국가</th>
<th align="center">통화명</th>
<th align="center">ISO 코드</th>
</tr>
</thead>
<tbody><tr>
<td align="center">미국</td>
<td align="center">달러</td>
<td align="center">USD</td>
</tr>
<tr>
<td align="center">유럽 연합</td>
<td align="center">유로</td>
<td align="center">EUR</td>
</tr>
<tr>
<td align="center">영국</td>
<td align="center">파운드</td>
<td align="center">GBP</td>
</tr>
<tr>
<td align="center">일본</td>
<td align="center">옌</td>
<td align="center">JPY</td>
</tr>
<tr>
<td align="center">호주</td>
<td align="center">달러</td>
<td align="center">AUD</td>
</tr>
<tr>
<td align="center">뉴질랜드</td>
<td align="center">달러</td>
<td align="center">NZD</td>
</tr>
<tr>
<td align="center">캐나다</td>
<td align="center">달러</td>
<td align="center">CAD</td>
</tr>
<tr>
<td align="center">스위스</td>
<td align="center">프랑</td>
<td align="center">CHF</td>
</tr>
<tr>
<td align="center">노르웨이</td>
<td align="center">크로네(krone)</td>
<td align="center">NOK</td>
</tr>
<tr>
<td align="center">스웨덴</td>
<td align="center">크로네(krona)</td>
<td align="center">SEK</td>
</tr>
<tr>
<td align="center">덴마크</td>
<td align="center">크로네(krone)</td>
<td align="center">DKK</td>
</tr>
</tbody></table>
<hr>
<h2 id="hedge-헤지">Hedge (헤지)</h2>
<p>투자자가 가지고 있거나 앞으로 보유하려는 자산의 가치가 변함에 따라 발생하는 위험을 없애려는 시도.</p>
<hr>
<h2 id="interdealer--interbank-market">Interdealer / Interbank Market</h2>
<p>FX 딜러들 간에 거래가 일어나는 마켓. 딜러는 클라이언트와 언제든지 통화를 매매할 준비가 되어 있는 금융 중개자이다. 환율 변화에 따른 위험에 대처할 수 있는 은행, 보험회사, 연금 기구, 대기업이 포함된다.</p>
<hr>
<h2 id="iso-4217-currency-code">ISO 4217 Currency Code</h2>
<p>Internation Organization for Standardization (ISO)에서 1973년에 제정한 <strong>3자리</strong> 화폐 코드. 앞의 두 자리는 국가명이고 마지막 한 자리는 화폐명이다.</p>
<ul>
<li>KRW - KR (대한민국) + W (원)</li>
<li>NZD - NZ (뉴질랜드) + D (달러)</li>
</ul>
<hr>
<h2 id="levarage-레버리지">Levarage (레버리지)</h2>
<p>필요 마진(Required Margin)에 몇 배에 해당하는 포지션을 열 수 있게 브로커들이 레버리지를 제공한다. </p>
<p>레버리지가 50:1 인 경우</p>
<ul>
<li>$2,000의 필요 마진을 가지고 $1,000,000의 EUR/USD 포지션을 열 수 있다.</li>
</ul>
<hr>
<h2 id="liquidity-유동성">Liquidity (유동성)</h2>
<p>활성도를 나타내는 단어. 특정 통화 페어를 사고 파는 활성 거래자 수와 거래되는 거래량을 기반으로 한다. 자주 거래될 수록 유동성이 더 높다.</p>
<hr>
<h2 id="long">Long</h2>
<p>Buy 와 같은 말이다. <em>Buy</em> 참조</p>
<hr>
<h2 id="lot">Lot</h2>
<p>외환 거래에서는 <strong>&quot;lot&quot;</strong> 으로 unit(화폐 단위) 을 이야기한다.</p>
<ul>
<li>1,000 units = micro lot</li>
<li>10,000 units = mini lot</li>
<li>100,000 units = lot / standard lot</li>
</ul>
<hr>
<h2 id="major--minor-cross-currency-pairs">Major / Minor Cross-Currency Pairs</h2>
<p>주요 통화 페어 중 <strong>미국 달러를 포함하지 않는</strong> 페어들. <em>&quot;crosses&quot;</em> 또는 <em>&quot;minors&quot;</em> 라고도 불린다. USD를 포함하지 않으면서 가장 활발히 거래되는 crosses 는 EUR, JPY, GBP 이다.</p>
<hr>
<h2 id="major-currencies-주요-통화">Major Currencies (주요 통화)</h2>
<p>다음의 8가지 통화를 주요 통화라고 부른다. ABC 순으로 나열했다.</p>
<table>
<thead>
<tr>
<th align="center">코드</th>
<th align="center">국가</th>
<th align="center">통화</th>
<th align="center">별칭</th>
</tr>
</thead>
<tbody><tr>
<td align="center">AUD</td>
<td align="center">호주</td>
<td align="center">달러</td>
<td align="center">Aussie</td>
</tr>
<tr>
<td align="center">CAD</td>
<td align="center">캐나다</td>
<td align="center">달러</td>
<td align="center">Loonie</td>
</tr>
<tr>
<td align="center">CHF</td>
<td align="center">스위스</td>
<td align="center">프랑</td>
<td align="center">Swissy</td>
</tr>
<tr>
<td align="center">EUR</td>
<td align="center">유로존</td>
<td align="center">유로</td>
<td align="center">Fiber</td>
</tr>
<tr>
<td align="center">GBP</td>
<td align="center">영국</td>
<td align="center">파운드</td>
<td align="center">Cable</td>
</tr>
<tr>
<td align="center">JPY</td>
<td align="center">일본</td>
<td align="center">옌</td>
<td align="center">Yen</td>
</tr>
<tr>
<td align="center">NZD</td>
<td align="center">뉴질랜드</td>
<td align="center">달러</td>
<td align="center">Kiwi</td>
</tr>
<tr>
<td align="center">USD</td>
<td align="center">미국</td>
<td align="center">달러</td>
<td align="center">Buck</td>
</tr>
</tbody></table>
<hr>
<h2 id="major-currency-pair">Major Currency Pair</h2>
<p>주요 통화 페어 중 <strong>미국 달러 (USD)를 포함하는</strong> 페어. 가장 활발히 거래된다. 아래 7가지 페어를 말한다.</p>
<table>
<thead>
<tr>
<th align="center">통화 페어</th>
<th align="center">국가</th>
<th align="center">속칭 발음</th>
</tr>
</thead>
<tbody><tr>
<td align="center">EUR/USD</td>
<td align="center">유로존 / 미국</td>
<td align="center">&quot;euro dollar&quot;</td>
</tr>
<tr>
<td align="center">USD/JPY</td>
<td align="center">미국 / 일본</td>
<td align="center">&quot;dollar yen&quot;</td>
</tr>
<tr>
<td align="center">GBP/USD</td>
<td align="center">영국 / 미국</td>
<td align="center">&quot;pound dollar&quot;</td>
</tr>
<tr>
<td align="center">USD/CHF</td>
<td align="center">미국 / 스위스</td>
<td align="center">&quot;dollar swissy&quot;</td>
</tr>
<tr>
<td align="center">USD/CAD</td>
<td align="center">미국 / 캐나다</td>
<td align="center">&quot;dollar loonie&quot;</td>
</tr>
<tr>
<td align="center">AUD/USD</td>
<td align="center">호주 / 미국</td>
<td align="center">&quot;aussie dollar&quot;</td>
</tr>
<tr>
<td align="center">NZD/USD</td>
<td align="center">뉴질랜드 / 미국</td>
<td align="center">&quot;kiwi dollar&quot;</td>
</tr>
</tbody></table>
<hr>
<h2 id="markup-이윤">Markup (이윤)</h2>
<p>FX 브로커들이 Primary OTC Market에서 찾은 상품에 붙이는 이윤. 이윤을 붙여 Secondary OTC Market에서 거래가 될 수 있도록 그들의 플랫폼에 올려 놓는다.</p>
<hr>
<h2 id="nokie">Nokie</h2>
<p>노르웨이 크로네(NOK)의 별명.</p>
<hr>
<h2 id="options-통화-옵션">Options (통화 옵션)</h2>
<p>통화옵션 거래란 미래의 특정시점(만기일 또는 만기 이전)에 특정 통화를 미리 약정한 가격으로 사거나(call option) 팔수 있는 권리(put option)를 매매하는 거래를 말한다. 유동성이 선물, 현물 시장에 비해 낮은 것이 단점이다.</p>
<hr>
<h2 id="otc--over-the-counter">OTC / Over-the-counter</h2>
<p>거래소 밖에서 벌어지는 시장. 장외시장을 뜻한다. 은행의 네트워크 안에서 온라인으로 24시간 지속되는 것이 특징이다.</p>
<hr>
<h2 id="pence">Pence</h2>
<p>Penny 의 복수형</p>
<hr>
<h2 id="pip--percentage-in-point--price-interest-point">Pip / Percentage in Point / Price Interest Point</h2>
<p>두 통화 사이의 변화를 설명하는 단위가 <strong>pip</strong> 이다. <strong>Pip은 보통 소수점 자리의 마지막을 의미한다.</strong> 대부분의 페어에서 소수점 네번째 자리를 의미하지만 일본 엔화는 두번째 자리이다.</p>
<p>EUR/USD 의 환율이 1.1050에서 1.1051로 변경되었으면 1 pip이 변경된 것이다.</p>
<p><img src="https://images.velog.io/images/lee_choonghee/post/a5deab65-9c50-4769-a3d0-751a509ab00c/pip_cheat_sheet.png" alt=""></p>
<hr>
<h2 id="pipette--point--fractional-pip">Pipette / Point / Fractional Pip</h2>
<p><em>pip</em> 의 10분의 1을 의미한다. pip이 소수점 4번째 자리를 의미하면, 5번째 자리가 pipette 가 된다.</p>
<hr>
<h2 id="primary-otc-market">Primary OTC Market</h2>
<p>인터딜러(interdealer)간에 일어나는 거래 시장.</p>
<hr>
<h2 id="required-margin-필요-마진">Required Margin (필요 마진)</h2>
<p>트레이더가 새로운 포지션을 열고 유지하는데 필요한 최소 금액.</p>
<hr>
<h2 id="retail-forex--secondary-otc-market">Retail Forex / Secondary OTC Market</h2>
<p>브로커(Trading Providers)가 <em>Primary OTC Market</em> 에서 가능한 최상의 가격을 찾아 <em>&quot;markup&quot;_을 붙여 브로커 자신의 거래 플랫폼에 가격을 올려놓고 거래가 이루어지는 시장을 말한다. 보통 개인 투자자들이기 때문에 _레버리지</em> 개념이 있다.</p>
<hr>
<h2 id="reservce-currency-기축-통화">Reservce Currency (기축 통화)</h2>
<p>국제간의 결제나 금융 거래의 기본이 되는 화폐. 현재는 미국의 달러와 일본의 엔 따위가 사용되고 있다.</p>
<hr>
<h2 id="rollover">Rollover</h2>
<p>브로커가 정한 마감 시간(cut-off time) 이후 열려있는 포지션에 따라서  <strong>&quot;rollover fee&quot;</strong> 또는 <strong>&quot;swap fee&quot;</strong> 라고 하는 것을 매일 지불하거나 지급받아야 한다. 빌린 통화에 대해서는 이자가 지불되고, 구매한 통화에 대해서는 이자가 지급된다. rollover율은 여러가지 요인에 의해 조정되니 계속 확인을 해야한다.</p>
<hr>
<h2 id="scandies">Scandies</h2>
<p><strong>덴마크, 노르웨이, 스웨덴</strong>을 합쳐 스칸디나비아라고 부르는 것에 유래하여 이들 국가의 통화들을 합쳐서 부르는 말.</p>
<hr>
<h2 id="sell">Sell</h2>
<p>통화를 판다는 것은 사실 Base Currency 를 팔고 Quote Currency 를 구매한다는 말이다. <em>Bid</em> 가격에 Base Currency 를 판다.</p>
<hr>
<h2 id="short">Short</h2>
<p>Sell과 같은 말이다. <em>Sell</em> 참조.</p>
<hr>
<h2 id="speculation-투기">Speculation (투기)</h2>
<p>시세 변동을 예상하여 차익을 얻기 위하여 하는 매매 거래.</p>
<hr>
<h2 id="spread-스프레드">Spread (스프레드)</h2>
<p>Bid와 Ask의 가격 차를 <strong>Spread</strong> 라고 부른다.</p>
<p>각 상품은 구매가와 판매가를 가진다. 그 차액(구매가-판매가)을 스프레드라고 부른다.</p>
<hr>
<h2 id="spread-bet-스프레드-베팅">Spread Bet (스프레드 베팅)</h2>
<p>자산에 대한 소유권은 없지만 미래에 해당 자산 가격이 오를지 내릴지 예측하는 파생 상품. 통화 페어에 가격에 방향에 대해 예측을 한다. 미국에서는 도박과 같은 불법 수준으로 여겨진다.</p>
<hr>
<h2 id="spot-fx--fx-spot">Spot FX / FX Spot</h2>
<p>외환 거래를 특정 환율에 따라 교환하기로 약정한 날을 D일(=거래일)이라고 하면, 그 계약에 따라 실제로 통화의 교환이 일어나는 날짜(=결제일)에 따라 상품을 구분해 놓은 것 중 하나이다.</p>
<table>
<thead>
<tr>
<th align="center">이름</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">FX Today</td>
<td align="center">당일 결제 (결제일 = 거래일)</td>
</tr>
<tr>
<td align="center">FX TOM(Tomorrow)</td>
<td align="center">거래 후 1 영업일에 결제 (결제일 = 거래일 + 영업일 1일)</td>
</tr>
<tr>
<td align="center">FX Spot</td>
<td align="center">거래 후 2 영업일에 결제 (결제일 = 거래일 + 영업일 2일)</td>
</tr>
<tr>
<td align="center">FX Forward</td>
<td align="center">거래 후 2 영업일이 지난 시점에 결제 (결제일 = 거래일 + 영업일 2일 이후)</td>
</tr>
</tbody></table>
<p>특징은 다음과 같다.</p>
<ul>
<li>중앙 거래소를 통하지 않고 인터딜러간에 다이렉트로 거래가 발생한다.</li>
<li>은행, 보험 회사, 연금 기구, 대기업 등이 여기에 해당한다.</li>
<li>통화를 거래하는 것이 아닌 그 <strong>계약을 거래하는 것</strong>이다.</li>
<li>Spot의 경우 결제일을 <em>T+2(&quot;Today plus 2 business days&quot;)</em> 라고 부른다.</li>
<li>개인 투자자들과는 상관이 없다.</li>
</ul>
<hr>
<h2 id="stockie">Stockie</h2>
<p>스웨덴 크로나(SEK)의 별명.</p>
<hr>
<h2 id="t2">T+2</h2>
<p>Today plus 2 business days. <em>Spot FX</em> 참조.</p>
<hr>
<h2 id="value-date--delivery-date">Value Date / Delivery Date</h2>
<p>결제일. <em>Spot FX</em> 참조.</p>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<ul>
<li><a href="https://www.babypips.com/">Babypips</a></li>
<li><a href="https://ko.dict.naver.com/#/main">네이버 국어사전</a></li>
<li><a href="https://en.dict.naver.com/#/main">네이버 영어사전</a></li>
<li><a href="http://www.dt.co.kr/contents.html?article_no=2016121902101857031001">디지털타임스 - 통화옵션시장 의의와 거래구조</a></li>
<li><a href="http://www.econovill.com/news/articleView.html?idxno=369689">이코노믹리뷰 - 통화 ETF, 美 달러선물 단기 방향성투자</a></li>
<li><a href="https://bizatoz.tistory.com/170">하얀 캔버스 - 결제일별로 분류한 상품유형</a></li>
<li><a href="https://www.fpmarkets.com/ko/what-are-cfds/">fpmarkets - CFD란?</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 동등 연산자 vs 일치 연산자]]></title>
            <link>https://velog.io/@lee_choonghee/JS-%EB%8F%99%EB%93%B1-%EC%97%B0%EC%82%B0%EC%9E%90-vs-%EC%9D%BC%EC%B9%98-%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@lee_choonghee/JS-%EB%8F%99%EB%93%B1-%EC%97%B0%EC%82%B0%EC%9E%90-vs-%EC%9D%BC%EC%B9%98-%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Sat, 25 Sep 2021 08:43:52 GMT</pubDate>
            <description><![CDATA[<p>누군가 <strong>동등 연산자(==, Equality Operator)와 일치 연산자(===, Strict Equality Operator)</strong>에 대해 질문한 것을 커뮤니티 게시판에 올려두었다. 갑자기 호기심이 동하여 어떻게 동작하는지 찾아보았다.</p>
<h1 id="모두가-아는-그-내용">모두가 아는 &#39;그 내용&#39;</h1>
<p>자바스크립트를 처음 공부할 때, 잘 모르겠으면 <code>===</code> 를 쓰라고 배우는 _&#39;그 내용&#39;_에 대해 간단히 짚어보고 가자. 그냥 없으면 허전하니까... 😙</p>
<ul>
<li><code>==</code> 동등 비교는 LHS의 값과 RHS의 값이 같은지 비교한다. <strong>중요한 것은 값을 비교한다는 것</strong>이다.</li>
<li><code>===</code> 일치 비교는 LHS의 값, 타입과 RHS의 값, 타입이 같은지 비교한다. <strong>중요한 것은 값과 타입 둘다 비교한다는 것</strong>이다.</li>
</ul>
<h2 id="optional-lhs--rhs">[Optional] LHS / RHS?</h2>
<p>내가 평소에 자주 쓰는 용어가 아니지만 공부 중에 등장해서 뜻을 적어본다.</p>
<ul>
<li>LHS: Left Hand Side</li>
<li>RHS: Right Hand Side</li>
</ul>
<h1 id="v8에서는-어떻게-동작할까-🤔">V8에서는 어떻게 동작할까? 🤔</h1>
<p>사실 오늘 알아보고싶은 내용은 V8엔진에서 두 연산자들이 어떻게 동작하는지이다. 두 연산자들의 실행 코드를 보기전에 _<strong>Runtime Functions</strong>_에 대해 알아본다.</p>
<h2 id="runtime-functions">Runtime Functions</h2>
<blockquote>
<p>V8 엔진의 빌트인 함수 중 일부는 곧장 자바스크립트로 구현되어 있고, 런타임에 실행가능한(executable) 코드로 컴파일됩니다. 이들 중 일부는 <em><strong>runtime functions</strong></em> 라고 분류되는 것들이 있습니다. C++로 작성되어 있고 자바스크립트에서 <code>%</code>-접두사를 붙여 호출합니다. 이러한 runtime functions은 V8 내부의 자바스크립트 코드에서만 사용됩니다. &lt;생략&gt; 일부 runtime functions는 컴파일러에 의해 생성된 코드에 삽입됩니다. </br>
<a href="https://v8.dev/docs/builtin-functions">Built-in functions, V8 doc</a></p>
</blockquote>
<p>내가 이해한 바로는, V8 내부의 자바스크립트 코드를 통해 실행되는 함수 중 그 기능을 온전히 하기 위해 런타임에 C++로 작성된 runtime functions를 삽입해준다는 것이다. 고마운 분께서 V8 런타임 함수의 리스트를 만들어 주셨다. 여기에서 <code>StrictEquality</code>와 <code>Equals</code>, 두 개의 런타임 함수를 찾을 수 있었다.</p>
<p><a href="https://github.com/hilongjw/v8-RuntimeFunctions-list">v8-RuntimeFunctions-list</a></p>
<h2 id="일치-연산자--strict-equality">일치 연산자 (===, Strict Equality)</h2>
<p>일단, 코드가 쉬워보이는(<del>짧아서</del>) 이유로 일치 연산자 부터 알아본다.</p>
<h3 id="런타임-함수">런타임 함수</h3>
<p>일치 연산자에서는 어떤 런타임 함수가 사용되는지 코드를 찾아보았다. 코드는 <a href="https://github.com/v8/v8/blob/main/src/runtime/runtime-operators.cc">runtime-operator.cc</a> 파일에서 찾을 수 있다.</p>
<pre><code class="language-cpp">RUNTIME_FUNCTION(Runtime_StrictEqual) {
  SealHandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_CHECKED(Object, x, 0);
  CONVERT_ARG_CHECKED(Object, y, 1);
  return isolate-&gt;heap()-&gt;ToBoolean(x.StrictEquals(y));
}</code></pre>
<p>코드의 내용을 해석해본다.</p>
<ul>
<li><a href="https://v8docs.nodesource.com/node-0.8/de/ded/classv8_1_1_isolate_1_1_scope.html">Isolate::Scope 클래스 문서</a>를 참조해보면, 지역 스코프 내에서 실행되는 모든 연산(operation)에 대해 isolate를 설정하는 스택처럼 할당되는 클래스라고 나와있다. 다른 스레드가 함부로 끼어들지 못하도록 락을 거는 것과 같은 느낌이라고 생각을 했다. <strong>단지 내 생각일 뿐이다!</strong></li>
<li><strong>_DCHECK_EQ_는 인수의 개수가 2개인지 확인한다.</strong> 일치 연산자는 두 가지를 가지고 비교하는 것이기 때문에 확인한다.</li>
<li>첫 번째 <strong><em>CONVERT_ARG_CHECKED</em></strong>를 해석해보자면, <strong>0번째 인덱스의 인수를 x라는 이름의 변수에 Object 타입으로 캐스팅한다</strong>는 얘기이다.</li>
<li><strong><em>StrictEquals</em></strong> 함수를 통해 일치 비교를 실행한다.<h3 id="비교-코드">비교 코드</h3>
여기까지 일치 연산자에 대한 런타임 함수를 살펴보았고, 실제 비교하는 코드를 살펴본다. <a href="https://github.com/v8/v8/blob/master/src/objects/objects.cc">objects.cc</a> 파일에서 찾을 수 있다.</li>
</ul>
<pre><code class="language-cpp">bool Object::StrictEquals(Object that) {
  if (this-&gt;IsNumber()) {
    if (!that.IsNumber()) return false;
    return StrictNumberEquals(*this, that);
  } else if (this-&gt;IsString()) {
    if (!that.IsString()) return false;
    return String::cast(*this).Equals(String::cast(that));
  } else if (this-&gt;IsBigInt()) {
    if (!that.IsBigInt()) return false;
    return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(that));
  }
  return *this == that;
}</code></pre>
<p>위 코드의 주요점은 <strong>타입이 다르면 <code>return false;</code>를 한다</strong>는 것이다. 그 후에 값을 비교한다.</p>
<h3 id="알고리즘">알고리즘</h3>
<p>ECMA가 정의한 일치 연산자 알고리즘(Strict Equality Comparison Algorithm)은 다음과 같다. 그냥 한 번 읽어보는게 좋을 것 같아서 소개해본다.</p>
<ol>
<li>x와 y의 타입이 다르면 <strong>false</strong>를 리턴한다.</li>
<li>x와 y의 타입이 _Undefined_면 <strong>true</strong>를 리턴한다.</li>
<li>x와 y의 타입이 _Null_이면 <strong>true</strong>를 리턴한다.</li>
<li>x의 타입이 <em>Number</em> 일 때,
 a. x의 값이 <strong>NaN</strong>이면 <strong>false</strong>를 리턴한다.
 b. y의 값이 <strong>NaN</strong>이면 <strong>false</strong>를 리턴한다.
 c. x와 y의 값이 같은 Number 값이면 <strong>true</strong>를 리턴한다.
 d. x가 +0이고 y가 -0일 때, <strong>true</strong>를 리턴한다.
 e. x가 -0이고 y가 +0일 때, <strong>true</strong>를 리턴한다.
 f. <strong>false</strong>를 리턴한다.</li>
<li>x의 타입이 String일 때, x와 y의 문자 순서와 그 값이 정확이 일치하면 <strong>true</strong>를 리턴하고 아니라면 <strong>false</strong>를 리턴한다.</li>
<li>x의 타입이 Boolean일 때, x와 y가 모두 true이거나 false이면 <strong>true</strong>를 리턴하고 아니라면 <strong>false</strong>를 리턴한다.</li>
<li>x와 y가 같은 객체를 참조하면 <strong>true를</strong> 리턴하고, 아니라면 <strong>false</strong>를 리턴한다.</li>
</ol>
<h2 id="동등-연산자-연산자--equality">동등 연산자 연산자 (==, Equality)</h2>
<p>이번엔 <del>코드가 길어서 미뤄왔던</del> 동등 연산자에 대해서 알아본다.</p>
<h3 id="런타임-함수-1">런타임 함수</h3>
<p>동등 연산자에서도 런타임 함수를 찾아 보았다. 이 코드 또한 <a href="https://github.com/v8/v8/blob/main/src/runtime/runtime-operators.cc">runtime-operator.cc</a> 파일에서 찾을 수 있다.</p>
<pre><code class="language-cpp">RUNTIME_FUNCTION(Runtime_Equal) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
  Maybe&lt;bool&gt; result = Object::Equals(isolate, x, y);
  if (result.IsNothing()) return ReadOnlyRoots(isolate).exception();
  return isolate-&gt;heap()-&gt;ToBoolean(result.FromJust());
}</code></pre>
<p><code>===</code> 연산자와의 차이와 특징을 살펴본다.</p>
<ul>
<li><em>StrictEquals</em> 대신 <strong><em>Equals</em></strong> 함수를 호출한다.</li>
<li>Maybe는 값이 있을 수도 없을 수도 있는 객체를 표현한다.</li>
<li>ReadOnlyRoots 에서 Roots 라는 단어를 정확히 어떤 의미로 사용했는지 모르겠다. 해당 클래스에 주석이 안 달려있다. ReadOnlyHeap 이라는 읽기 전용 공간, 루트, 캐쉬 생성과 파괴를 관리하는 클래스가 있는데, Heap이라는 자료 구조의 Root를 이야기하는 것이 아닐까 추측해본다... 도와주세요 🙇🏾‍♀️</li>
</ul>
<h3 id="비교-코드-1">비교 코드</h3>
<p>동등 연산자의 실제 비교 코드를 살펴본다. 역시 <a href="https://github.com/v8/v8/blob/master/src/objects/objects.cc">objects.cc</a> 파일에서 찾을 수 있었다. 꽤 길다 ^^;</p>
<pre><code class="language-cpp">Maybe&lt;bool&gt; Object::Equals(Isolate* isolate, Handle&lt;Object&gt; x,
                           Handle&lt;Object&gt; y) {
  while (true) {
    if (x-&gt;IsNumber()) {
      if (y-&gt;IsNumber()) {
        return Just(StrictNumberEquals(x, y));
      } else if (y-&gt;IsBoolean()) {
        return Just(
            StrictNumberEquals(*x, Handle&lt;Oddball&gt;::cast(y)-&gt;to_number()));
      } else if (y-&gt;IsString()) {
        return Just(StrictNumberEquals(
            x, String::ToNumber(isolate, Handle&lt;String&gt;::cast(y))));
      } else if (y-&gt;IsBigInt()) {
        return Just(BigInt::EqualToNumber(Handle&lt;BigInt&gt;::cast(y), x));
      } else if (y-&gt;IsJSReceiver()) {
        if (!JSReceiver::ToPrimitive(Handle&lt;JSReceiver&gt;::cast(y))
                 .ToHandle(&amp;y)) {
          return Nothing&lt;bool&gt;();
        }
      } else {
        return Just(false);
      }
    } else if (x-&gt;IsString()) {
      if (y-&gt;IsString()) {
        return Just(String::Equals(isolate, Handle&lt;String&gt;::cast(x),
                                   Handle&lt;String&gt;::cast(y)));
      } else if (y-&gt;IsNumber()) {
        x = String::ToNumber(isolate, Handle&lt;String&gt;::cast(x));
        return Just(StrictNumberEquals(x, y));
      } else if (y-&gt;IsBoolean()) {
        x = String::ToNumber(isolate, Handle&lt;String&gt;::cast(x));
        return Just(
            StrictNumberEquals(*x, Handle&lt;Oddball&gt;::cast(y)-&gt;to_number()));
      } else if (y-&gt;IsBigInt()) {
        return BigInt::EqualToString(isolate, Handle&lt;BigInt&gt;::cast(y),
                                     Handle&lt;String&gt;::cast(x));
      } else if (y-&gt;IsJSReceiver()) {
        if (!JSReceiver::ToPrimitive(Handle&lt;JSReceiver&gt;::cast(y))
                 .ToHandle(&amp;y)) {
          return Nothing&lt;bool&gt;();
        }
      } else {
        return Just(false);
      }
    } else if (x-&gt;IsBoolean()) {
      if (y-&gt;IsOddball()) {
        return Just(x.is_identical_to(y));
      } else if (y-&gt;IsNumber()) {
        return Just(
            StrictNumberEquals(Handle&lt;Oddball&gt;::cast(x)-&gt;to_number(), *y));
      } else if (y-&gt;IsString()) {
        y = String::ToNumber(isolate, Handle&lt;String&gt;::cast(y));
        return Just(
            StrictNumberEquals(Handle&lt;Oddball&gt;::cast(x)-&gt;to_number(), *y));
      } else if (y-&gt;IsBigInt()) {
        x = Oddball::ToNumber(isolate, Handle&lt;Oddball&gt;::cast(x));
        return Just(BigInt::EqualToNumber(Handle&lt;BigInt&gt;::cast(y), x));
      } else if (y-&gt;IsJSReceiver()) {
        if (!JSReceiver::ToPrimitive(Handle&lt;JSReceiver&gt;::cast(y))
                 .ToHandle(&amp;y)) {
          return Nothing&lt;bool&gt;();
        }
        x = Oddball::ToNumber(isolate, Handle&lt;Oddball&gt;::cast(x));
      } else {
        return Just(false);
      }
    } else if (x-&gt;IsSymbol()) {
      if (y-&gt;IsSymbol()) {
        return Just(x.is_identical_to(y));
      } else if (y-&gt;IsJSReceiver()) {
        if (!JSReceiver::ToPrimitive(Handle&lt;JSReceiver&gt;::cast(y))
                 .ToHandle(&amp;y)) {
          return Nothing&lt;bool&gt;();
        }
      } else {
        return Just(false);
      }
    } else if (x-&gt;IsBigInt()) {
      if (y-&gt;IsBigInt()) {
        return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y)));
      }
      return Equals(isolate, y, x);
    } else if (x-&gt;IsJSReceiver()) {
      if (y-&gt;IsJSReceiver()) {
        return Just(x.is_identical_to(y));
      } else if (y-&gt;IsUndetectable()) {
        return Just(x-&gt;IsUndetectable());
      } else if (y-&gt;IsBoolean()) {
        y = Oddball::ToNumber(isolate, Handle&lt;Oddball&gt;::cast(y));
      } else if (!JSReceiver::ToPrimitive(Handle&lt;JSReceiver&gt;::cast(x))
                      .ToHandle(&amp;x)) {
        return Nothing&lt;bool&gt;();
      }
    } else {
      return Just(x-&gt;IsUndetectable() &amp;&amp; y-&gt;IsUndetectable());
    }
  }
}</code></pre>
<p>길어서 좀 압박이 있었을 수도 있겠지만, 결국 <strong>필요할 때 캐스팅해서 값을 비교하는 것</strong>이다. 코드보다는 아래의 알고리즘을 읽어보는게 훨씬 나을 것 같다 😌.</p>
<h3 id="알고리즘-1">알고리즘</h3>
<p>ECMA의 동등 연산자 알고리즘(Abstract Equality Comaprison Algorithm)은 다음과 같다. </p>
<ol>
<li>x와 y의 타입이 같다면,
 a. x의 타입이 Undefined면 <strong>true</strong>를 리턴한다.
 b. x의 타입이 Null이면 <strong>true</strong>를 리턴한다.
 c. x의 타입이 Number 라면,<pre><code> &amp;emsp;i. &amp;nbsp&amp;nbspx가 **NaN** 라면, **false**를 리턴한다.
 &amp;emsp;ii. &amp;nbspy가 **NaN** 라면, **false**를 리턴한다.
 &amp;emsp;iii. x와 y값이 같으면 **true**를 리턴한다.
 &amp;emsp;iv.&amp;nbspx가 +0이고 y가 -0일 때, true를 리턴한다.
 &amp;emsp;v.&amp;nbsp&amp;nbspx가 -0이고 y가 +0일 때, true를 리턴한다.
 &amp;emsp;vi.&amp;nbsp**false**를 리턴한다.</code></pre>d. x의 타입이 String일 때, x와 y의 문자 순서와 그 값이 정확이 일치하면 <strong>true</strong>를 리턴하고 아니라면 <strong>false</strong>를 리턴한다.
e. x의 타입이 Boolean일 때, x와 y가 모두 true이거나 false이면 <strong>true</strong>를 리턴하고 아니라면 <strong>false</strong>를 리턴한다.</li>
<li>x가 <strong>null</strong>이고 y가 <strong>undefined</strong>면 <strong>true</strong>를 리턴한다.</li>
<li>x가 <strong>undefined</strong>이고 y가 <strong>null</strong>이면 <strong>true</strong>를 리턴한다.</li>
<li>x가 Number 타입이고 y가 String 타입일 때, <strong>x == ToNumber(y)</strong>의 결과를 리턴한다.</li>
<li>x가 String 타입이고 y가 Number 타입일 때, <strong>ToNumber(x) == y</strong>의 결과를 리턴한다.</li>
<li>x의 타입이 Boolean 이면, <strong>ToNumber(x) == y</strong>의 결과를 리턴한다.</li>
<li>y의 타입이 Boolean 이면, <strong>x == ToNumber(y)</strong>의 결과를 리턴한다.</li>
<li>x가 String 이나 Number 타입이고 y가 Object 타입일 때, <strong>x == ToPrimitive(y)</strong>의 결과를 리턴한다.</li>
<li>x가 Object 타입이고 y가 String 이나 Number 타입일 때, <strong>ToPrimitive(x) == y</strong>의 결과를 리턴한다.</li>
<li><strong>false</strong>를 리턴한다.</li>
</ol>
<h1 id="optional-재미있는-사이트">[Optional] 재미있는(?) 사이트</h1>
<p>내용이 너무 딱딱한 것 같아서 동등, 비교 연산자와 관련한 재미있는(?) 사이트를 소개한다. 비교 연산자를 한 눈에 볼 수 있는 척 하게 해주는 사이트이다 ㅋㅋㅋ. 
<a href="https://dorey.github.io/JavaScript-Equality-Table/">JavaScript Equality Table</a></p>
<h1 id="소감">소감</h1>
<p>지금까지 자바스크립트를 가장한 C++ 코드 블로깅이었다. 자바와 JS의 간단하게 하면 간단하게 끝나는 내용을 깊게 알아보기 위해 C++와 자료구조를 잘 알고 있어야 한다는 느낌을 많이 받았다. 이게 무슨 소용인지 가치가 있는 일인지 헷갈리지만, 그냥 엉덩이 붙히고 앉아서 오랜 시간 하나의 내용을 찾아보는 것을 해내고 있다는 것으로 위안을 삼고있다. 낄낄 😏</p>
<h1 id="참고한-자료">참고한 자료</h1>
<ul>
<li><a href="https://github.com/v8/v8">Github - v8/v8 Repository</a></li>
<li><a href="http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&amp;mallGb=KOR&amp;barcode=9791158392239&amp;orderClick=LAG&amp;Kc=">모던 자바스크립트 Deep Dive, 이웅모, 위키북스</a></li>
<li><a href="https://v8.dev/docs/builtin-functions">V8 - Builtin Functions</a></li>
<li><a href="https://v8docs.nodesource.com/node-0.8/index.html">V8 - API Reference</a></li>
<li><a href="https://262.ecma-international.org/">ECMAScript® Language Specification</a></li>
<li><a href="https://dorey.github.io/JavaScript-Equality-Table/">JavaScript Equality Table</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] IntegerCache를 만나봤니?]]></title>
            <link>https://velog.io/@lee_choonghee/Java-IntegerCache%EB%A5%BC-%EB%A7%8C%EB%82%98%EB%B4%A4%EB%8B%88</link>
            <guid>https://velog.io/@lee_choonghee/Java-IntegerCache%EB%A5%BC-%EB%A7%8C%EB%82%98%EB%B4%A4%EB%8B%88</guid>
            <pubDate>Sun, 12 Sep 2021 12:38:59 GMT</pubDate>
            <description><![CDATA[<p>Integer 래퍼 클래스에는 <code>IntegerCache</code> 클래스가 내부에 존재한다. <strong>IntegerCache가 어떻게 동작하는지 알아보고</strong> <strong>실제로 캐싱이 되는지 확인해 볼 것이다</strong>.</p>
<ul>
<li><strong>[Optional]</strong> 이라고 표시된 섹션은 건너뛰어도 읽는데 지장이 없다.</li>
<li>의식의 흐름대로 공부 중이니 제목에 어긋나는 내용도 있을 수 있다.<h1 id="integer">Integer</h1>
일단 Integer가 어떤 클래스인지 정의를 정확히 보고 싶었다.<blockquote>
<p><strong>Integer</strong> 클래스는 primitive type인 int를 감싸는 객체이다.
Integer 객체는 타입이 int인 단일 필드를 포함한다.
<br><em><a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Integer.html">Java 11 공식 문서</a></em></p>
</blockquote>
</li>
</ul>
<h2 id="optional-공식-문서에서-필드-확인-✅">[Optional] 공식 문서에서 필드 확인 ✅</h2>
<p>_&quot;Integer 객체는 타입이 int인 단일 필드를 포함한다.&quot;_라는 문장에 꽂혀서 확인해보고자 공식 문서를 찾아보았다. 그런데...
<img src="https://images.velog.io/images/lee_choonghee/post/365da212-7355-4be8-8bf6-858d00de259e/integer_field_summary.png" alt="Integer filed summary">
엥? 없는데요? ㅋㅋㅋㅋ. 시작부터 난관이 예상된다. IntelliJ에서 코드를 찾아보니 AdoptOpenJDK 11 기준으로 1062~1067번 줄에서 찾을 수 있었다.</p>
<pre><code class="language-java">/**
* The value of the {@code Integer}.
*
* @serial
*/
private final int value;</code></pre>
<p>코드에 멀쩡히 살아있음 + 문서용 주석인데, 왜 공식 문서에는 나오지 않는 걸까?</p>
<p>여러 문서 페이지를 돌아다녀보니 <code>public</code>, <code>protected</code>로 선언된 변수들만 <code>Field Summary</code> 섹션에 나온다. <strong>&quot;이럴거면 private 변수에 문서용 주석은 왜 달아놓는데?&quot;</strong>라는 생각 + <strong>&quot;진짜로 private로 선언되어 있으면 문서에 못 들어가나?&quot;</strong>에 대한 의문이 떠오르면서 한 단계 더 나아가 보기로 했다.</p>
<h2 id="optional-private-변수를-문서에-포함시키기">[Optional] private 변수를 문서에 포함시키기</h2>
<p>항상 궁금한걸 해봐야 직성이 풀리지는 않지만, 한 단계 더 나아가는 습관을 만들기 위해 노오오오오오오오력 해본다 💪!
<img src="https://images.velog.io/images/lee_choonghee/post/07e63591-9a70-4fc1-a9be-a1a2cfd96fe6/%E1%84%83%E1%85%A9%E1%84%85%E1%85%A1%E1%84%8B%E1%85%A6%E1%84%86%E1%85%A9%E1%86%BC-%E1%84%8C%E1%85%A9%E1%86%B7%E1%84%83%E1%85%A5%E1%84%82%E1%85%A9%E1%84%85%E1%85%A7%E1%86%A8%E1%84%92%E1%85%A2%E1%84%8B%E1%85%A3%E1%84%83%E1%85%AC%E1%86%AB%E1%84%83%E1%85%A1.jpeg" alt="도라에몽-노력해야 된다">
아래의 코드를 작성했다.</p>
<pre><code class="language-java">public class Main {

    /**
     * public 으로 선언된 인스턴스 변수
     */
    public int num = 1;

    /**
     * protected 으로 선언된 인스턴스 변수
     */
    protected double doubleNum = 1;

    /**
     * package-private 으로 선언된 인스턴스 변수
     */
    boolean isTrue = true;

    /**
     * private 으로 선언된 인스턴스 변수
     */
    private String str = &quot;Hello&quot;;

    public static void main(String[] args) {}
}</code></pre>
<p>그리고 다음과 같이 <code>javadoc</code> 명령어를 실행한다.</p>
<pre><code class="language-bash">$ javadoc Main.java</code></pre>
<p>생성된 파일들 중 패키지명으로된 폴더들을 따라 들어가서 <code>Main.html</code>열어본다. 그럼 Field Summary가 아래와 같이 나타난다.
<img src="https://images.velog.io/images/lee_choonghee/post/16b791ec-5b9e-4be0-9ae0-214afa378d13/Screen%20Shot%202021-09-08%20at%2013.39.56.png" alt="javadoc field summary">
<code>javadoc</code>의 디폴트 동작이 <code>public</code>, <code>protected</code>만 나오게 되어있다는 것을 확인했다.</p>
<p>내가 하고싶은 것은 <strong>&quot;private 변수도 문서에 껴주시라요&quot;</strong> 이기 때문에, <code>javadoc --help</code>로 옵션질(?)을 해보도록 한다. </p>
<p>여담이지만, 어느순간 <a href="https://www.hyundai.com/kr/ko/e/vehicles/avante/price">자동차 카탈로그의 옵션</a>을 읽는 것보다 커맨드라인 명령어의 옵션을 보는 것이 더 쉬워졌다. 자동차 옵션은 무슨 말인지 하나도 모르겠다.</p>
<p>찾았다!</p>
<pre><code class="language-text">-private
    Show all types and members. For named modules,
        show all packages and all module details.</code></pre>
<p>보면 쉽지만, 안 찾아보면 평생 모를법한 옵션이다. 적용해보자!</p>
<pre><code class="language-bash">$ javadoc -private Main.java</code></pre>
<p>다시 Main.html을 열어보면
<img src="https://images.velog.io/images/lee_choonghee/post/8fd86e60-045d-4b80-8079-0c954e34df37/Screen%20Shot%202021-09-08%20at%2013.54.55.png" alt="javadoc private field summary">
<code>private</code>, <code>package-private</code> 변수가 모두 포함되어 있다!</p>
<p>혹시 여기까지 읽었다면 미안하게 생각한다. 의식의 흐름대로 공부하며 글을 적는 중이다 😜.. <strong>본론으로 돌아가자!</strong></p>
<h1 id="integercache">IntegerCache</h1>
<p><code>IntegerCache</code>도 <code>private</code> 클래스이기 때문에 Integer 문서에 나타나지 않는다. IntelliJ에서 코드를 확인해보면 다음과 같은 설명이 나온다.</p>
<blockquote>
<p>Cache to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive) as required by JLS<br>
AdoptOpenJDK 11</p>
</blockquote>
<p>무슨 말인지 이해는 되는데 한글로 못 적겠는 그런거 내 맘 알지 😜?
<img src="https://images.velog.io/images/lee_choonghee/post/a1a0811d-8563-466d-83ee-9d09c14acc63/%E1%84%82%E1%85%A2%E1%84%86%E1%85%A1%E1%86%B7%E1%84%8B%E1%85%A1%E1%86%AF%E1%84%8C%E1%85%B5.png" alt="내 맘 알지"></p>
<blockquote>
<p>-128과 127 사이의 값을 오토박싱한 객체가 유일함을 캐싱한다.<br>
초 간단 번역</p>
</blockquote>
<p>번역 피드백 좀 주십쇼... 🙇🏻‍♂️</p>
<h2 id="코드-살펴보기-🕵🏽♀️">코드 살펴보기 🕵🏽‍♀️</h2>
<p>이거 구글에 검색해보면 다 나오는거지만 나도 한 번 해보겠다. <strong>AdoptOpenJDK 11 버전</strong>의 코드를 기준으로 한다.</p>
<pre><code class="language-java">private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // 캐싱 가능한 최대 int 값은 디폴트가 127이다.
        int h = 127;
        // 시스템 프로퍼티 -Djava.lang.Integer.IntegerCache.high 또는
        // JVM 옵션 -XX:AutoBoxCacheMax을 설정한 경우
        // 캐싱 가능한 최대값 설정
        String integerCacheHighPropValue =
            VM.getSavedProperty(&quot;java.lang.Integer.IntegerCache.high&quot;);
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // int로 파싱이 불가능하면 무시한다.
            }
        }
        high = h;

        // 캐싱 배열에 Integer 객체 미리 만들어 삽입
        // -128부터 127까지 미리 만들어 놓는다!
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k &lt; cache.length; k++)
            cache[k] = new Integer(j++);

        // 캐싱 가능한 최대 int 값은 127보다 같거나 커야한다.
        // 위의 i = Math.max(i, 127); 코드에서 알아서 걸러준다.
        assert IntegerCache.high &gt;= 127;
    }

    private IntegerCache() {}
}</code></pre>
<p>어떻게 동작하는지 살펴보았다. 다른 Wrapper 클래스들도 이런 캐싱을 하는지 궁금해졌다.</p>
<h2 id="optional-다른-wrapper-클래스들의-cache-클래스">[Optional] 다른 Wrapper 클래스들의 Cache 클래스</h2>
<p>확인을 직접해보니 Boolean, Float, Double 형 빼고 정수형 Wrapper 클래스들은 각자의 Cache 클래스가 있다. <strong>구현 코드를 보니 JVM 옵션으로 최대 캐싱값을 설정하는 곳은 없었다</strong>. 그냥 <strong>-128~127 사이의 값 고정이다</strong>.</p>
<p>다음은 <code>ByteCache</code> 의 구현 코드이다. <code>ShortCache</code>, <code>LongCache</code> 의 구현도 타입만 다를 뿐 모두 같다.</p>
<pre><code class="language-java">private static class ByteCache {
    private ByteCache(){}

    static final Byte cache[] = new Byte[-(-128) + 127 + 1];

    static {
        for(int i = 0; i &lt; cache.length; i++)
            cache[i] = new Byte((byte)(i - 128));
    }
}</code></pre>
<p><code>CharacterCache</code>는 구현 코드가 조금 다르다. 근본은 정수 타입이지만 문자를 표현하기 위한 타입이므로 <strong>음수값을 캐싱하지 않는다</strong>.</p>
<pre><code class="language-java">private static class CharacterCache {
    private CharacterCache(){}

    static final Character cache[] = new Character[127 + 1];

    static {
        for (int i = 0; i &lt; cache.length; i++)
            cache[i] = new Character((char)i);
    }
}</code></pre>
<h1 id="integer로-메모리를-터트려보자-💣">Integer로 메모리를 터트려보자 💣</h1>
<p>갑자기 왠 메모리를 터트려보자? ㅋㅋㅋㅋ 실제로 Integer 객체를 캐싱하는지 알아보려면 같은 값의 Integer 객체 2개를 선언하고 <code>==</code>로 비교해보면 쉽게 알 수 있다. 하지만 뭔가 밋밋하고 재미가 없어서 메모리를 터트려보려고 한다. <strong>목표는 java.lang.OutOfMemoryError 이다!</strong></p>
<h2 id="가비지-컬렉션-동작-금지-✋🏻">가비지 컬렉션 동작 금지! ✋🏻</h2>
<p>아무리 무한 루프로 열심히 객체를 생성한다 한들 가비지 컬렉터가 싹 정리해 버리면 소용이 없다. 그래서 <strong>가비지 컬렉팅을 금지시켜야 겠다</strong>고 생각을 했다. 그래서 열심히 찾아낸 것이 <strong><a href="https://openjdk.java.net/jeps/318">Epsilon GC</a></strong>이다.</p>
<h3 id="epsilon-a-no-op-garbage-collector">Epsilon: A No-Op Garbage Collector</h3>
<blockquote>
<p>메모리 할당을 처리하지만 <strong>회수 메커니즘을 구현하지 않는 GC</strong>를 개발해보세요. 사용 가능한 Heap이 소진되면 JVM이 종료됩니다.<br>
<a href="https://openjdk.java.net/jeps/318">OpenJDK JEP 381 - Epsilon GC</a></p>
</blockquote>
<p>와우! 할당은 하지만 회수를 하지 않는 지금 나의 실험에 꼭 필요한 도구이다! 엡실론 가비지 컬렉터를 적용하려면 다음과 같은 옵션을 주면된다.</p>
<pre><code class="language-text">-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC</code></pre>
<p>Baeldung의 <a href="https://www.baeldung.com/author/attila-fejer/">Attila Fejér 선생님</a>(?)은 도대체 이런걸 어떻게 알았는지 정말 신기하다... 🤪</p>
<h2 id="최소--최대-메모리-옵션">최소 &amp; 최대 메모리 옵션</h2>
<p>빠른 폭파를 위해 추가적으로 최소, 최대 메모리 옵션을 똑같이 작게 할당했다.</p>
<pre><code class="language-text">-Xms128m -Xmx128m</code></pre>
<h2 id="무한-루프를-돌려보자">무한 루프를 돌려보자</h2>
<p>프로그래밍에서 무한 루프 작성은 위험 덩어리라고 배우지만 OutOfMemoryError가 목표이므로 돌려보도록 하겠다. 돌려돌려 돌림판~!<img src="https://images.velog.io/images/lee_choonghee/post/1a4da10b-8672-4fd2-87b4-0dabb9fb6aa0/%E1%84%83%E1%85%A9%E1%86%AF%E1%84%85%E1%85%A7%E1%84%83%E1%85%A9%E1%86%AF%E1%84%85%E1%85%A7%E1%84%83%E1%85%A9%E1%86%AF%E1%84%85%E1%85%B5%E1%86%B7%E1%84%91%E1%85%A1%E1%86%AB.gif" alt=""></p>
<p>코드는 정말로 별거 없음 그 자체이다.</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        while(true) {
            // Integer i = 1;
            Integer i = 999;
            System.out.println(i);
        }
    }
}</code></pre>
<p>먼저 Integer 객체의 값을 999로 놓고 돌려본다. -XX:AutoBoxCacheMax 옵션을 따로 주지 않았으니 캐싱이 안될 것 이므로 메모리 폭파를 예상했고 결과는 다음과 같다.</p>
<pre><code class="language-text">...
999
999
999
Terminating due to java.lang.OutOfMemoryError: Java heap space</code></pre>
<p>굿 👍</p>
<p>다음은 값을 1로 놓고 돌려본다. 캐싱이 되는 범위에 있으므로 프로그램이 계속 살아있음을 예상했고 결과는 다음과 같다.</p>
<pre><code class="language-text">...
1
1
1
Terminating due to java.lang.OutOfMemoryError: Java heap space</code></pre>
<p>?! 저기요 님은 왜 터지시죠..? 정말 한참 고민했다. 생각해보니        <code>System.out.println(i);</code> 이 코드에서 PrintStream에서 Output Stream들이 할당된다는 것을 깨달았다. Epsilon GC가 메모리 공간 해제를 안 해주니 이것들이 쌓여서 이런 결과가 나왔음을 발견했다.</p>
<p>코드를 다시 수정했다.</p>
<pre><code class="language-java">while(true) {
    Integer i = 1;
    // Integer i = 999;
}</code></pre>
<p>안 터지고 계속 돌아간다 :D</p>
<p>999의 주석을 해제하고 실행시켜보았다. 안 터지고 계속 돌아간다... 어얽... 터져야 되는데?? 😓 그럼 앞에서 터진 것도 Integer 값이 999인 객체를 계속 생성해서 그런 것이 아니었다는 말이다. 에효효효효효효</p>
<h2 id="5시간의-고민-끝에">5시간의 고민 끝에...</h2>
<p>위의 코드를 계속 돌렸다 멈췄다 디버깅했다가 검색했다가 생각했다가를 반복하니 5시간이 흘렀다. 진짜 뜬금없이 <strong>옛날에 Visual Studio에서 C++ 코딩을 할 때, 컴파일러 최적화 옵션을 줄 수 있고 기본적으로 최적화를 해주었던게 기억이 났다.</strong> 혹시나 하는 마음에 자바 컴파일러도 최적화를 해주는지 찾아보았다.</p>
<h2 id="jit-컴파일러-최적화-4단계">JIT 컴파일러 최적화 4단계</h2>
<p>다음의 코드를 작성하면 JIT 컴파일러가 어떻게 최적화하는지 예제와 함께 매우 간단하게만 알아본다.</p>
<pre><code class="language-java">class A {
    B b;
    public void foo() {
        y = b.get();
        ...do stuff...
        z = b.get();
        sum = y + z;
    }
}
class B {
    int value;
    final int get() {
        return value;
    }
}</code></pre>
<h3 id="1-inline-final-method">1. Inline final method</h3>
<p>1단계를 거치면 <code>b.get()</code> <strong>메소드를 호출하는 대신 바로 값으로 치환</strong>한다. 접근 시간을 조금이라도 줄일 수 있다.</p>
<pre><code class="language-java">public void foo() {
    y = b.value; // 바뀐 부분
    ...do stuff...
    z = b.value; // 바뀐 부분
    sum = y + z;
}</code></pre>
<h3 id="2-remove-redundant-loads">2. Remove redundant loads</h3>
<p><code>b.value</code> 코드에 접근하는 것보다 <strong>지역 변수에 접근하게 하여 속도를 빠르게 한다</strong>.</p>
<pre><code class="language-java">public void foo() {
    y = b.value;
    ...do stuff...
    z = y; // 바뀐 부분
    sum = y + z;
}</code></pre>
<h3 id="3-copy-propagation">3. Copy propagation</h3>
<p>굳이 z라는 <strong>추가적인 변수를 사용할 필요가 없기 때문에</strong> y로 바꿔버렸다.</p>
<pre><code class="language-java">public void foo() {
    y = b.value;
    ...do stuff...
    y = y; // 바뀐 부분
    sum = y + z;
}</code></pre>
<h3 id="4-eliminate-dead-code">4. Eliminate dead code</h3>
<p><code>y = y</code>는 <strong>불필요한 동작이므로 지워버렸다</strong>.</p>
<pre><code class="language-java">public void foo() {
    y = b.value;
    ...do stuff...
    // 바뀐 부분
    sum = y + z;
}</code></pre>
<p>JIT 컴파일러가 4단계를 거쳐 코드 최적화를 해주는 것을 보았다. 물론 더 깊게 봤으면 하는 아쉬움이 있지만 글이 너무나도 길어질 것 같아 따로 주제를 빼서 해야할 것 같다.</p>
<h2 id="jit-컴파일러-비활성화-하기">JIT 컴파일러 비활성화 하기</h2>
<p>나의 실험 코드 <code>Integer i = 999;</code>가 JIT 컴파일러에 의해 제거되므로 JIT 컴파일러를 비활성화 하기로 마음먹었다. 다음과 같은 옵션을 주면 된다.</p>
<pre><code class="language-text">-Djava.compiler=NONE</code></pre>
<p>다시 코드를 돌려보자!</p>
<pre><code class="language-java">while(true) {
    // Integer i = 1;
    Integer i = 999;
}</code></pre>
<pre><code class="language-text">Terminating due to java.lang.OutOfMemoryError: Java heap space</code></pre>
<p>ㅅㄱ... 드디어 끝났다!</p>
<h1 id="결론">결론</h1>
<p>IntegerCache가 동작한다는 것을 내부 구현 코드만 봐도 알 수 있지만 뭔가 색다르게 증명해보고 싶었다. 그 와중에 알게된 것도 많고 깊게 공부하려는 습관을 만드는데 많은 도움이 된 것 같다. 재미있는 시간이었다! 💪</p>
<h1 id="참고한-자료">참고한 자료</h1>
<ul>
<li><a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Integer.html">Javadoc - Integer</a></li>
<li><code>javadoc --help</code></li>
<li><a href="https://github.com/AdoptOpenJDK/openjdk-jdk11">Github - AdoptOpenJDK/openjdk-jdk11</a></li>
<li><a href="https://www.baeldung.com/jvm-epsilon-gc-garbage-collector">Baeldung - An Introduction to Epsilon GC</a></li>
<li><a href="https://openjdk.java.net/jeps/318">EJP 318: Epsilon: A No-Op Garbage Collector</a></li>
<li><a href="https://www.youtube.com/watch?v=aTMZGs0ZGPE">Cameron McKenzie - How to Stop Java GC and Prevent Garbage Collection on the JVM</a></li>
<li><a href="https://stackoverflow.com/questions/5242405/how-to-disable-compiler-and-jvm-optimizations">StackOverFlow - How to disable compiler and JVM optimizations?</a></li>
<li><a href="https://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/underst_jit.html">Oracle - Understanding JIT Compilation and Optimizations</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] main 메소드 뽀개기]]></title>
            <link>https://velog.io/@lee_choonghee/Java-main-%EB%A9%94%EC%86%8C%EB%93%9C-%EB%BD%80%EA%B0%9C%EA%B8%B0</link>
            <guid>https://velog.io/@lee_choonghee/Java-main-%EB%A9%94%EC%86%8C%EB%93%9C-%EB%BD%80%EA%B0%9C%EA%B8%B0</guid>
            <pubDate>Sat, 11 Sep 2021 16:57:17 GMT</pubDate>
            <description><![CDATA[<h1 id="발단">발단</h1>
<p>자바 책을 펼쳤다. Hello World 예제가 나오면서 main 메소드는 이렇게 생겨먹은거니 일단 넘어가란다. 내가 펼친 책은 자바를 처음 배우는 사람을 위해 쓰여졌지만, 나는 처음 배우는 사람이 아니므로 <em>&quot;그러라 그래~&quot;</em> 식으로 넘어가면 안될 것 같았다. 보통은 프로그래밍 공부하면서 통하지 않는 방법이다. 하지만 이번에는 <em>&quot;그냥 그래라&quot;</em> 하긴 해야한다.</p>
<h1 id="어떻게-생겨먹었나">어떻게 생겨먹었나</h1>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        System.out.println(&quot;Hello World&quot;);
    }
}</code></pre>
<p><strong>psvm</strong>으로 외워보고 <strong>public static void main(String[] args)</strong>라고도 외워보고 자바를 처음 배울때 왜 이렇게 안 외워졌는지 모르겠다. 그런데 한가지 표현법이 더 있다. 별건 아니고 <strong>가변인자(variable arguments; varargs)</strong>를 사용하는 것이다.</p>
<pre><code class="language-java">public static void main(String... args)</code></pre>
<p>저렇게 적어두면 실행해보지 않아도 IDE가 먼저 반응할 것이다.</p>
<h1 id="public">public</h1>
<p>흔히 알고있는 접근 제어자(access modifier) public이다. <strong><em>어디에서나 누구나 main 메서드에 접근 가능하다</em></strong>는 뜻이라는 것은 대부분 알 것이다. 그럼 왜 꼭 public 이어야할까? 사실 JVM을 만드는 사람이 어떤 접근 제어자에 상관없이 하려면 그렇게 만들 수 있을 것이다. 하지만 <strong>public이어야 한다고 JVM 코드에 못박혀져있다</strong>.</p>
<h1 id="jvm에서의-main-메소드-호출">JVM에서의 main 메소드 호출</h1>
<p>나도 public에 대해 쓰려다가 JVM에서 main 메소드가 어떻게 호출되는지 쓰게될지 전혀 몰랐다 🤣. OpenJDK7의 <a href="http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/tools/launcher/java.c">java.c</a>라는 파일에 적힌 내용을 살펴보았다. C언어를 잘 몰라도 고수님들이 함수이름을 예쁘게 적어두었기 때문에 흐름을 파악하는 수준에서는 큰 무리가 없었다. 읽기 쉬운 코드 작성의 필요성을 다시 한 번 느낀다.</p>
<pre><code class="language-c">// 중간에 생략된 코드가 많습니다.

// main 메소드가 있는 클래스를 로딩한다.
mainClassName = GetMainClassName(env, jarfile);
mainClass = LoadClass(env, classname);

// main 메소드의 아이디를 찾는다.
mainID = (*env)-&gt;GetStaticMethodID(env, mainClass, &quot;main&quot;, &quot;([Ljava/lang/String;)V&quot;);

/*
  mainClass, mainID를 가지고 
  java.lang.reflect.Method 객체로 변환한다.
  JNI_TRUE면 static 메소드를 찾는다.
*/
jbject obj = (*env)-&gt;ToReflectedMethod(env, mainClass, mainID, JNI_TRUE);

/*
  위에서 찾은 Method 객체를 이용하여 
  getModifiers라는 메소드의 아이디를 찾는다.
*/
mid = (*env)-&gt;GetMethodID(env, (*env)-&gt;GetObjectClass(env, obj), &quot;getModifiers&quot;, &quot;()I&quot;);

// getModifiers 메소드를 이용하여 
// main 메소드의 접근지시자를 알아낸다.
// public이 아니면 안된다!
mods = (*env)-&gt;CallIntMethod(env, obj, mid);
if ((mods &amp; 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */
    message = &quot;Main method not public.&quot;;
    messageDest = JNI_TRUE;
    goto leave;
}

// String[] args를 가져온다.
mainArgs = NewPlatformStringArray(env, argv, argc);

// 드디어 실행시킨다!
(*env)-&gt;CallStaticVoidMethod(env, mainClass, mainID, mainArgs);</code></pre>
<p>OpenJDK7 이라 미안하다. 여기 코드가 하나의 파일에 모여있어서 찾아보기 쉬워서 그랬다... <del>시간이 되면 11버전으로 업데이트를 해보겠다.</del></p>
<h1 id="다시-public">다시 public</h1>
<p>JVM이 main 메소드는 public이라고 강제한다는 것까지 알아보았다. 그럼 실제로 다른 접근 지시자를 적으면 어떻게 될까?</p>
<pre><code class="language-java">private static void main(String[] args) {
    System.out.println(&quot;Hello World&quot;);
}</code></pre>
<p><code>private</code> 키워드로 실행해보면...</p>
<pre><code class="language-text">Error: Main method not found in class com.choonghee.MainMethod, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application</code></pre>
<p>main 메소드를 찾을 수 없다고 에러를 발생시킨다! 다른 접근 지시자들도 마찬가지의 에러를 뱉어낸다. 물론, 실행전에 IDE가 먼저 반응할 것 이다. 👅</p>
<h1 id="static">static</h1>
<p>static 키워드는 _<strong>인스턴스 생성없이 메서드를 호출할 수 있음</strong>_을 의미한다. JVM 코드에서 살펴봤듯이 main 메소드 실행시 <code>JNI_TRUE</code>로 static 메소드를 찾는다. 이건 납득이 간다. <strong>굳이 메모리 공간 차지해가면서 main 메소드를 실행시킬 인스턴스를 만들 이유가 없기 때문이다.</strong></p>
<p>이번에는 static 키워드를 없애고 실행해봤다.</p>
<pre><code class="language-text">Error: Main method is not static in class com.choonghee.MainMethod, please define the main method as:
   public static void main(String[] args)</code></pre>
<p>main 메소드에 static 키워드가 없다고 에러를 발생시킨다.</p>
<h1 id="void">void</h1>
<p>void는 <em><strong>메소드의 리턴 값이 없음을 의미한다</strong></em>. JVM이 <code>CallStaticVoidMethod</code> 함수를 호출시킨다. 그러므로 void 키워드여야 한다. 이것도 이해가 간다. 자바는 메소드에 리턴 타입이 있을 때 암묵적으로 값을 알아서 넘겨주는 언어가 아니다. 그리고 <strong>프로그램이 끝나는 마당에 리턴값을 넘겨줄 필요가 없다.</strong>  물론 정상적인 종료를 판단하기 위해 int를 리턴하는 C같은 언어도 있다.</p>
<p>리턴 타입을 다른 타입으로 변경하고 실행해봤다.</p>
<pre><code class="language-text">Error: Main method must return a value of type void in class com.choonghee.MainMethod, please 
define the main method as:
   public static void main(String[] args)</code></pre>
<p>main 메소드의 리턴 타입을 void로 해달라고 에러를 발생시킨다.</p>
<h1 id="main">main</h1>
<p>JVM이 main 메소드 아이디를 찾는 부분에서 <strong>메소드명 인수에 &quot;main&quot;이라고 하드 코딩이 되어있다.</strong> 이것은 Java가 C언어의 영향을 받았기 때문에 협상의 여지가 없다. </p>
<p>여담이지만 C언어는 B언어의 영향을 받았다. <a href="https://www.bell-labs.com/usr/dmr/www/btut.pdf">B언어 튜토리얼</a>을 보면, 프로그램의 시작은 main 부터 시작이라고 적혀있다.</p>
<pre><code class="language-B">-- General Layout of B Programs -- 

main( ) {
-- statements --
}
newfunc(arg1, arg2) {
-- statements --
}
fun3(arg) {
-- more statements --
}</code></pre>
<p>main이라는 이름 대신 다른 이름을 적으면, main 메서드를 찾을 수 없다는 에러가 발생한다.</p>
<h1 id="string-args">String[] args</h1>
<p><strong>커맨드 라인의 argument들을 의미한다</strong>. JVM이 main 메소드의 변수명을 강제하지 않으니 변수명은 마음대로 바꿔도 잘 동작한다. JVM의 <code>main</code> 함수에서 arguments들을 가져와서 main 메소드까지 여러 과정을 거쳐서 보내준다.</p>
<pre><code class="language-c">// 여기서 커맨드 라인의 인자들을 받아온다.
int main(int argc, char ** argv)

/*
struct JavaMainArgs {
  int     argc;
  char ** argv;
  char *  jarfile;
  char *  classname;
  InvocationFunctions ifn;
};
*/

// JavaMain 함수를 호출하기 위해 인자를 세팅한다.
struct JavaMainArgs args;
args.argc = argc;
args.argv = argv;
args.jarfile = jarfile;
args.classname = classname;
args.ifn = ifn;

// JavaMain을 새로운 스레드에서 호출한다.
ContinueInNewThread(JavaMain, threadStackSize, (void*)&amp;args);

// JavaMain이다.
int JNICALL JavaMain(void * _args)

// 문자열 배열로 변신!
int argc = args-&gt;argc;
char **argv = args-&gt;argv;
mainArgs = NewPlatformStringArray(env, argv, argc);</code></pre>
<p><strong>역시나 JVM이 문자열 배열이여야 한다고 했기 때문에 String[]여야 한다.</strong> </p>
<p>다른 타입으로 바꿔보고 실행해봤다.</p>
<pre><code class="language-text">Error: Main method not found in class com.choonghee.MainMethod, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application</code></pre>
<p>main 메소드를 알아보지 못 한다!</p>
<h1 id="결론">결론</h1>
<p>제목에 <em>[Java]_라고 적어놨지만 C 코드를 더 많이 봤다. <strong>main 메소드에 대한 나의 결론은 JVM이 _&quot;그러라 그래&quot;_라고 말해주는 것이다.</strong> 왜 JVM이 그렇게 동작하도록 만들었는지 이유를 찾아서 알려주고 싶지만 고슬링 선생님을 만나봐야 알 것 같다. 답장을 줄지는 모르겠지만 DM을 한 번 날려보겠다. 응답이 있다면 다시 블로깅을 해보겠다!! _I miss you ~</em> 💪
<img src="https://images.velog.io/images/lee_choonghee/post/232e2579-f613-4d6b-922f-92cb0d7ed107/%E1%84%8C%E1%85%A6%E1%84%8B%E1%85%B5%E1%86%B7%E1%84%89%E1%85%B3%E1%84%80%E1%85%A9%E1%84%89%E1%85%B3%E1%86%AF%E1%84%85%E1%85%B5%E1%86%BC.jpg" alt="제임스 고슬링"></p>
<h3 id="dm-보냈습니다-답장-기다려봅니다">DM 보냈습니다. 답장 기다려봅니다!</h3>
<h1 id="참고한-자료">참고한 자료</h1>
<ul>
<li><a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.1.4">Java Language Specification - SE 8 Edition</a></li>
<li><a href="http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/tools/launcher/java.c">OpenJDK 7 Hotspot Launcher - Java.c</a></li>
<li><a href="https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html">Oracle JNI Functions</a></li>
<li><a href="https://www.javatpoint.com/java-main-method">Java T Point- Java Main Method</a></li>
<li><a href="https://www.bell-labs.com/usr/dmr/www/btut.pdf">A TUTORIAL INTRODUCTION TO THE LANGUAGE B</a></li>
<li><a href="https://en.wikipedia.org/wiki/Java_(programming_language)">Wikipedia - Java</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>