<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Lullu Lalla</title>
    <link>https://binarycube.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 30 Jul 2026 17:39:17 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>merlin.park</managingEditor>
    <item>
      <title>코루틴 안내서 (Coroutine guide)  - Kotlin Coroutines 읽기 (#2)</title>
      <link>https://binarycube.tistory.com/12</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어로서 코틀린은 다양한 라이브러리들이 코루틴을 활요할 수 있도록 표준라이브러리를 통한 최소한의 기본적인 수준(low-level)의 API만을 제공합니다. 비슷한 기능을 가진 다른 프로그래밍 언어와는 다르게&amp;nbsp; async와 await는 코틀린에에서 뿐만 아니라 표준 라이브러리에서도 예약어(keyword)가 아닙니다. 더군다나 코틀린에서의 suspend function의 개념은 비동기 작업에 있어서 Promis나 Future보다 더 안전하고 에러로부터 자유로운 추상화를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kotlinx.coroutines은 JebBrains(Kotlin을 개발한 회사)에 의해 개발된 훌륭한(rich) 코루틴 라이브러리입니다. 이는 이 문서에서 다루는 코루틴에서 사용할 수 있는 여러개의 높은 수준(high-level)의 기초 요소들(launch, async 등)을 포함하고 있습니다.&lt;/p&gt;
&lt;p id=&quot;e251a700&quot; data-ke-size=&quot;size16&quot;&gt;이 글은 각 주제에 대하여 구분된 여러 예제를 통한 kotlinx.coroutines의 핵심 기능에 대한 안내서입니다. 코루틴을 이 가이드의 예제와 같이 사용하기 위해서는 &lt;a id=&quot;6ff74272&quot; href=&quot;https://github.com/Kotlin/kotlinx.coroutines/blob/master/README.md#using-in-your-projects&quot; data-test=&quot;external-link &quot;&gt;in the project README&lt;/a&gt; 문서에 설명된 것과 같이 kotlinx-coroutines-core 모듈을 프로젝트에 추가해야합니다.&lt;/p&gt;
&lt;h2 id=&quot;table-of-contents&quot; data-toc=&quot;table-of-contents&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;span&gt;내용 목차&lt;/span&gt;&lt;span data-clipboard-text=&quot;https://kotlinlang.org/docs/coroutines-guide.html#table-of-contents&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul id=&quot;9fe12195&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;12e5d35&quot;&gt;&lt;a id=&quot;d6518a57&quot; href=&quot;https://kotlinlang.org/docs/coroutines-basics.html&quot; data-test=&quot;internal-link &quot;&gt;Coroutines basics&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;1a9e8d58&quot;&gt;&lt;a id=&quot;e1ea0ea5&quot; href=&quot;https://play.kotlinlang.org/hands-on/Introduction%20to%20Coroutines%20and%20Channels&quot; data-test=&quot;external-link &quot;&gt;Hands-on: Intro to coroutines and channels&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;29e3e3a&quot;&gt;&lt;a id=&quot;511915c1&quot; href=&quot;https://kotlinlang.org/docs/cancellation-and-timeouts.html&quot; data-test=&quot;internal-link &quot;&gt;Cancellation and timeouts&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;92e90d5f&quot;&gt;&lt;a id=&quot;cb00b25d&quot; href=&quot;https://kotlinlang.org/docs/composing-suspending-functions.html&quot; data-test=&quot;internal-link &quot;&gt;Composing suspending functions&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;6cb42ae&quot;&gt;&lt;a id=&quot;16024c12&quot; href=&quot;https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html&quot; data-test=&quot;internal-link &quot;&gt;Coroutine context and dispatchers&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;6f044b7f&quot;&gt;&lt;a id=&quot;e7d1752c&quot; href=&quot;https://kotlinlang.org/docs/flow.html&quot; data-test=&quot;internal-link &quot;&gt;Asynchronous Flow&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;e935daac&quot;&gt;&lt;a id=&quot;4f93e7f2&quot; href=&quot;https://kotlinlang.org/docs/channels.html&quot; data-test=&quot;internal-link &quot;&gt;Channels&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;1ed4c00b&quot;&gt;&lt;a id=&quot;3fd0f197&quot; href=&quot;https://kotlinlang.org/docs/exception-handling.html&quot; data-test=&quot;internal-link &quot;&gt;Coroutine exceptions handling&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;c4d813fe&quot;&gt;&lt;a id=&quot;a69dee6f&quot; href=&quot;https://kotlinlang.org/docs/shared-mutable-state-and-concurrency.html&quot; data-test=&quot;internal-link &quot;&gt;Shared mutable state and concurrency&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;532187f2&quot;&gt;&lt;a id=&quot;9a633a28&quot; href=&quot;https://kotlinlang.org/docs/select-expression.html&quot; data-test=&quot;internal-link &quot;&gt;Select expression (experimental)&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;c3a79b07&quot;&gt;&lt;a id=&quot;f390e80e&quot; href=&quot;https://kotlinlang.org/docs/debug-coroutines-with-idea.html&quot; data-test=&quot;internal-link &quot;&gt;Tutorial: Debug coroutines using IntelliJ IDEA&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;d36faa41&quot;&gt;&lt;a id=&quot;1b5d0aa6&quot; href=&quot;https://kotlinlang.org/docs/debug-flow-with-idea.html&quot; data-test=&quot;internal-link &quot;&gt;Tutorial: Debug Kotlin Flow using IntelliJ IDEA&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;additional-references&quot; data-toc=&quot;additional-references&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;span&gt;Additional references&lt;/span&gt;&lt;span data-clipboard-text=&quot;https://kotlinlang.org/docs/coroutines-guide.html#additional-references&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;div data-test=&quot;article&quot;&gt;
&lt;ul id=&quot;47bc65e3&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;7ee71723&quot;&gt;&lt;a id=&quot;5f0db1eb&quot; href=&quot;https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md&quot; data-test=&quot;external-link &quot;&gt;Guide to UI programming with coroutines&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;39ca5885&quot;&gt;&lt;a id=&quot;26946dcc&quot; href=&quot;https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md&quot; data-test=&quot;external-link &quot;&gt;Coroutines design document (KEEP)&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;b5ba3f62&quot;&gt;&lt;a id=&quot;76989fcc&quot; href=&quot;https://kotlinlang.org/api/kotlinx.coroutines/&quot; data-test=&quot;external-link &quot;&gt;Full kotlinx.coroutines API reference&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;92a8f6a0&quot;&gt;&lt;a id=&quot;138f1abf&quot; href=&quot;https://developer.android.com/kotlin/coroutines/coroutines-best-practices&quot; data-test=&quot;external-link &quot;&gt;Best practices for coroutines in Android&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;d635d2b5&quot;&gt;&lt;a id=&quot;884f78eb&quot; href=&quot;https://developer.android.com/kotlin/coroutines/additional-resources&quot; data-test=&quot;external-link &quot;&gt;Additional Android resources for Kotlin coroutines and flow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Kotlin</category>
      <category>Coroutine</category>
      <category>Kotlin</category>
      <category>reading_kotlin_coroutine</category>
      <author>merlin.park</author>
      <guid isPermaLink="true">https://binarycube.tistory.com/12</guid>
      <comments>https://binarycube.tistory.com/12#entry12comment</comments>
      <pubDate>Thu, 19 Jan 2023 15:02:28 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin Coroutines 읽기 (#1)</title>
      <link>https://binarycube.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;오늘부터 시간이 날 때마다 코루틴 공식 문서 읽기를 번역해서 올려보려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Kotlin Coroutine 관련 스터디를 하고 있는데 이와 별개로 공식문서를 작은 Snippet 단위로 번역해보고 차근차근 읽어가보는게 도움이 될 것 같아서입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;링크는 번역 전에는 공식문서로 연결되고, 번역을 완료하면 포스팅된 글로 연결하겠습니다. 번역 우선순위는 자체적으로 판단해서 실무적으로 필요한 부분(실제 Kotlin Coroutine을 많이 사용하고 있기 때문에)부터 해볼 생각입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;저는 영어에 능통하지도 않고 번역과는 더더군다나 무관한 사람이기 때문에 잘못된 내용이 있을 수 있음을 참고해서 함께 읽어주시면 감사하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;비동기나 논블로킹 프로그램은 개발환경에서 중요한 부분입니다. 서버나 데스크탑, 혹은 모바일 어플리케이션을 만들 때, 사용자 관점에서 유연(fluid)할 뿐만 아니라 필요에 따라 확장가능(scaleable)하게 처리 할 수 있는 경험을 제공하는 것은 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Kotlin은 이 문제를 언어수준에서 Coroutine을 제공하고 기능을 라이브러리를 통해서 제공하므로서 유연하게 해결합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;비동기 프로그래밍의 문을 여는 것 외에도&amp;nbsp; &lt;span&gt;&lt;span&gt;&lt;span&gt;코루틴은 또한 Concurrency나 Actor와 같은 다양한 가능성을 제공합니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;How to start&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Kotlin을 처음 겪으신다면 &lt;a href=&quot;https://kotlinlang.org/docs/getting-started.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Getting started를&lt;/a&gt; 먼저 둘러보세요.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;목차&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul id=&quot;6014fd5&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;8ee50a8f&quot;&gt;&lt;a id=&quot;80a15bfb&quot; href=&quot;https://binarycube.tistory.com/12&quot; data-test=&quot;internal-link &quot;&gt;코루틴 안내서(Coroutines guide)&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;470cbc0c&quot;&gt;&lt;a id=&quot;438a1050&quot; href=&quot;https://kotlinlang.org/docs/coroutines-basics.html&quot; data-test=&quot;internal-link &quot;&gt;Basics&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;f70d5529&quot;&gt;&lt;a id=&quot;134f5fab&quot; href=&quot;https://kotlinlang.org/docs/channels.html&quot; data-test=&quot;internal-link &quot;&gt;Channels&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;d58282de&quot;&gt;&lt;a id=&quot;34f0b015&quot; href=&quot;https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html&quot; data-test=&quot;internal-link &quot;&gt;Coroutine context and dispatchers&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;801b9478&quot;&gt;&lt;a id=&quot;cead2c2e&quot; href=&quot;https://kotlinlang.org/docs/shared-mutable-state-and-concurrency.html&quot; data-test=&quot;internal-link &quot;&gt;Shared mutable state and concurrency&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;a4cc3e57&quot;&gt;&lt;a id=&quot;c7c2fee0&quot; href=&quot;https://kotlinlang.org/docs/flow.html&quot; data-test=&quot;internal-link &quot;&gt;Asynchronous flow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;튜토리얼&lt;/h4&gt;
&lt;ul id=&quot;433e728&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;b60fd44a&quot;&gt;&lt;a id=&quot;ffaca467&quot; href=&quot;https://kotlinlang.org/docs/async-programming.html&quot; data-test=&quot;internal-link &quot;&gt;Asynchronous programming techniques&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;532af913&quot;&gt;&lt;a id=&quot;39d9cc2b&quot; href=&quot;https://kotlinlang.org/docs/coroutines-and-channels.html&quot; data-test=&quot;internal-link &quot;&gt;Introduction to coroutines and channels&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;daf13978&quot;&gt;&lt;a id=&quot;ea3fc588&quot; href=&quot;https://kotlinlang.org/docs/debug-coroutines-with-idea.html&quot; data-test=&quot;internal-link &quot;&gt;Debug coroutines using IntelliJ IDEA&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;da9643dc&quot;&gt;&lt;a id=&quot;37f85611&quot; href=&quot;https://kotlinlang.org/docs/debug-flow-with-idea.html&quot; data-test=&quot;internal-link &quot;&gt;Debug Kotlin Flow using IntelliJ IDEA &amp;ndash; tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;1bfb5ea3&quot;&gt;&lt;a id=&quot;ead96236&quot; href=&quot;https://developer.android.com/kotlin/coroutines/test&quot; data-test=&quot;external-link &quot;&gt;Testing Kotlin coroutines on Android&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 프로젝트&lt;/h3&gt;
&lt;ul id=&quot;b416c796&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;23e9bf9c&quot;&gt;&lt;a id=&quot;5e2fa32f&quot; href=&quot;https://github.com/Kotlin/kotlin-coroutines/tree/master/examples&quot; data-test=&quot;external-link &quot;&gt;kotlinx.coroutines examples and sources&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;7e6ea39e&quot;&gt;&lt;a id=&quot;73480c70&quot; href=&quot;https://github.com/JetBrains/kotlinconf-app&quot; data-test=&quot;external-link &quot;&gt;KotlinConf app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Kotlin</category>
      <category>Coroutine</category>
      <category>Kotlin</category>
      <category>reading_coroutine</category>
      <author>merlin.park</author>
      <guid isPermaLink="true">https://binarycube.tistory.com/11</guid>
      <comments>https://binarycube.tistory.com/11#entry11comment</comments>
      <pubDate>Thu, 19 Jan 2023 14:47:00 +0900</pubDate>
    </item>
    <item>
      <title>Me</title>
      <link>https://binarycube.tistory.com/notice/10</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 궁금한 것들을 알아보고 정리하면서 글을 쓰고있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;짧은 글을 쓰는데도 생각보다 많은 시간이 든다는 탓으로 글을 많이 쓰지는 못했습니다만, 여전히 노력 중입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는 토스팀에서 서버개발을 하고 있습니다.&lt;/p&gt;</description>
      <author>merlin.park</author>
      <guid isPermaLink="true">https://binarycube.tistory.com/notice/10</guid>
      <pubDate>Wed, 18 Jan 2023 15:35:32 +0900</pubDate>
    </item>
    <item>
      <title>[Baeldung] Java의 Stack과 Heap 메모리(Stack Memory and Heap Space in Java)</title>
      <link>https://binarycube.tistory.com/8</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 Kotlin Coroutine을 공부하다 보니 Thread와 관련돼서 알아보게 되었고 JVM Memory에 관해서 다시 알아보다가 Baeldung에 최근에 올라온 글이 있어서 번역해보려고 합니다. 아래 목록을 참고하셔서 읽으시면 도움이 될 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로 제가 읽고 번역한 사항이고 부분적으로 Google 번역기를 이용하였습니다.&lt;/li&gt;
&lt;li&gt;원 글에서 Stack은 Memory로 표현했고 Heap은 Space로 표현했으나 둘 다 메모리 영역이고, Memory와 Space를 구분하는 게 무의미하여 Stack과 Heap으로만 표현했습니다.&lt;/li&gt;
&lt;li&gt;번역을 했으나 부자연스러운 부분은 물음표(?)로 표시해놓았으니 원글을 통해서 확인하시면 도움이 될 것 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 들어가면서 (Introduction)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Application을 효율적으로 구동하기 위해서 JVM 기기들은 메모리를 Stack과 Heap으로 구분해놓았습니다. 우리가 새로운 변수나 객체를 생성하거나, 함수를 호출하고 String 자료형을 선언하는 등의 행위를 할 때마다 JVM은 이를 수행하기 위해서 Stack이나 Heap의 메모리를 지정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이 글에서는 이러한 메모리 형태에 대해서 알아보고자 합니다. 먼저 우리는 이들에 대한 주요사항들을 둘러볼 거예요. 그런 다음 메모리(RAM)에저장하는 방법과 사용처에 대해 알아볼거예요. 마지막으로는 서로의 차이점에 대해서도 설명해 볼 거예요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Java에서의 Stack (Stack Memory in Java)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Java에서의 Stack Memory(이하 Stack)는 정적인 할당과 스레드를 실행하는 데 사용됩니다. 이는 메서드에 배정된 primitive type 변수와 Heap Space(이하 Heap)에 있는 메서드에 의해 참조된 객체에 대한 참조값을 갖고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Stack에 대한 접근은 후입선출(LIFO;Last-In-First-Out)로 작동합니다. 우리가 메서드를 호출할 때마다 primitive type 변수가 참조되는 객체와 같이 메서드에 할당된 값들을 갖고 있는 새로운 메모리 블럭이 스택의 상단에 생성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;메서드가 실행을 완료하게 되면, 이에 상응하는 메모리가 반환(flush)되고 호출된 메서드로 흐름이 이동하게 되며, 이후 메서드들이 공간을 이용할 수 있게 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1. Stack의 주요 내용 (Key Features fo Stack Memory)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Stack에 대한 다른 내용들은 다음과 같이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드가 호출되고 반환될 때마다 크기가 커지고 줄어듭니다.&lt;/li&gt;
&lt;li&gt;스택 내부의 변수는 변수를 생성한 메서드가 실행되는 동안에만 존재합니다.&lt;/li&gt;
&lt;li&gt;메서드 실행이 완료되면 자동으로 할당 해제됩니다.&lt;/li&gt;
&lt;li&gt;Stack이 가득 차면 Java에서 java.lang.StackOverFlowError 예외를 발생시킵니다.&lt;/li&gt;
&lt;li&gt;Heap에 비해 접근 속도가 빠릅니다.&lt;/li&gt;
&lt;li&gt;스레드는 각자의 스택에서 작동하므로 다른 스레드로부터 안전합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Java에서의 Heap (Heap Space in Java)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Heap은 런타임에 JRE 클래스들이나 Java 객체에 대해서 동적인 메모리 할당을 하는 데 사용됩니다. 새로운 객체는 항상 Heap에 생성되며 이 객체에 대한 참조값은 Stack에 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Heap에 존재하는 객체는 전역적으로 접근 가능하여 Application의 어느 곳에서나 접근이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Heap은 더 작게 구분된 형태인 제너레이션(Generation)이 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Young Generation -&lt;/b&gt; 여기는 객체가 새로 생성되면 할당되어 저장됩니다. 만약 가득 차게 되면 소규모의(minor) Garbage collection이 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Old or Tenured Generation -&lt;/b&gt; 여기는 오랫동안 살아남은 객체들이 저장되는 곳입니다. Young Generation에 객체가 저장될 때 객체의 수명에 대한 임계치(Threshold)가 설정되고, 그 임계치에 이르면 객체는 Old Teneration으로 이관됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Permanent Generation -&lt;/b&gt; 이곳은 런타임 클래스들과 Application 메서드들의 JVM 메타데이터가 저장되어있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이러한 차이점에 대해서는 &lt;a href=&quot;https://www.baeldung.com/jvm-vs-jre-vs-jdk&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Difference Between JVM, JRE and JDK&lt;/a&gt; 문서에서도 설명합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1. Heap의 주요내용 (Key Features of Java Heap Memory)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Heap에 대한 다른 내용들은 다음과 같이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Young Generation, Old or Tenured Generation, Permanent Generation을 포함하는 복합적인 메모리 관리 기술(Complex memory management techniqes)들에 의해 접근이 됩니다.(?)&lt;/li&gt;
&lt;li&gt;만약 Heap이 가득 차게 된다면 Java는 java.lang.OutOfMemoryError 예외를 발생시킵니다.&lt;/li&gt;
&lt;li&gt;Heap에 접근하는 것은 Stack에 접근하는 것보다 상대적으로 느립니다.&lt;/li&gt;
&lt;li&gt;Heap은 Stack과는 반대로 메모리가 자동으로 반환되지 않습니다. 메모리를 반환하기 위해서는 사용하지 않는 객체를 Garbage Collector가 반환해 줘야(free up) 합니다.&lt;/li&gt;
&lt;li&gt;Stack과는 다르게 Heap은 스레드에 안전하지 않고(isn't threadsafe) 코드를 동기화(synchronizing)하는 값(property)에 의해 보호되어야 합니다. (의역) threadsafety 하지 않아서, 코드 수준에서 동기화하는 데 있어서 고려해야합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 예제 (Example)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;지금까지 배운 것들에 기반하여 어떻게 메모리를 관리하는지에 대해 알아보는 간단한 Java 코드를 분석해 볼 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1674012788730&quot; class=&quot;arduino&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
    int id;
    String name;

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

public class PersonBuilder {
    private static Person buildPerson(int id, String name) {
        return new Person(id, name);
    }

    public static void main(String[] args) {
        int id = 23;
        String name = &quot;John&quot;;
        Person person = null;
        person = buildPerson(id, name);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;차근차근 코드를 분석해 볼까요?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;i&gt;main()&lt;/i&gt; 함수에 진입하게 되면 Stack 안에 privitive type 변수와 메서드에 대한 참조를 저장하기 위해 공간이 생성됩니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Stack은 정수값 &lt;i&gt;id&lt;/i&gt;의 primitive type 값을 직접적으로 저장합니다.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Person&lt;/i&gt; 자료형인 객체 &lt;i&gt;person&lt;/i&gt;에 대한 참조값은 Stack에 저장되며 이 값은 실제로 Heap 안에 있는 객체를 가리킵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;i&gt;main()&lt;/i&gt;에서 &lt;i&gt;Persion(int, String)&lt;/i&gt; 생성자를 호출하면, Stack의 상단에 추가적인 메모리가 할당되며 아래 내용을 저장합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Stack에서 호출하는 객체에 대한 &lt;i&gt;this&lt;/i&gt; 객체 참조&lt;/li&gt;
&lt;li&gt;Stack 안에 있는 primitive type 값인 &lt;i&gt;id&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;값 참조 변수인 &lt;i&gt;name(String)&lt;/i&gt;은 Heap 안에 있는 문자열 pool에 있는 실제 문자열을 가리킬 것입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;i&gt;main()&lt;/i&gt; 함수는 추가적으로 정적 메서드인 &lt;i&gt;buildPerson()&lt;/i&gt;을 호출하고 있고, 이를 위해 추가적인 할당을 Stack의 상단에 할 것입니다. 이후 위에서 설명한 방식으로 변수가 다시 저장됩니다.&lt;/li&gt;
&lt;li&gt;반면에 Heap은 새로 생성되는 &lt;i&gt;Person&lt;/i&gt; 타입의 &lt;i&gt;person&lt;/i&gt; 객체의 모든 인스턴스 변수들을 저장할 것입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;아래 다이어그램에 있는 할당 과정을 봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;java-heap-stack-diagram.webp&quot; data-origin-width=&quot;2826&quot; data-origin-height=&quot;1590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE2r6A/btrWx8VqcRO/KydrBzkngC60vARrjwvqv1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE2r6A/btrWx8VqcRO/KydrBzkngC60vARrjwvqv1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE2r6A/btrWx8VqcRO/KydrBzkngC60vARrjwvqv1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE2r6A%2FbtrWx8VqcRO%2FKydrBzkngC60vARrjwvqv1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2826&quot; height=&quot;1590&quot; data-filename=&quot;java-heap-stack-diagram.webp&quot; data-origin-width=&quot;2826&quot; data-origin-height=&quot;1590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 요약 (Summary)&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 405px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Parameter&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Stack&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Heap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 37px;&quot;&gt;Application&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 37px;&quot;&gt;Stack&amp;nbsp;is&amp;nbsp;used&amp;nbsp;in&amp;nbsp;parts,&amp;nbsp;one&amp;nbsp;at&amp;nbsp;a&amp;nbsp;time&amp;nbsp;during&amp;nbsp;execution&amp;nbsp;of&amp;nbsp;a&amp;nbsp;thread&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 37px;&quot;&gt;The&amp;nbsp;entire&amp;nbsp;application&amp;nbsp;uses&amp;nbsp;Heap&amp;nbsp;space&amp;nbsp;during&amp;nbsp;runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 55px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 55px;&quot;&gt;Size&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 55px;&quot;&gt;Stack&amp;nbsp;has&amp;nbsp;size&amp;nbsp;limits&amp;nbsp;depending&amp;nbsp;upon&amp;nbsp;OS,&amp;nbsp;and&amp;nbsp;is&amp;nbsp;usually&amp;nbsp;smaller&amp;nbsp;than&amp;nbsp;Heap&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 55px;&quot;&gt;There&amp;nbsp;is&amp;nbsp;no&amp;nbsp;size&amp;nbsp;limit&amp;nbsp;on&amp;nbsp;Heap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 55px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 55px;&quot;&gt;Storage&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 55px;&quot;&gt;Stores&amp;nbsp;only&amp;nbsp;primitive&amp;nbsp;variables&amp;nbsp;and&amp;nbsp;references&amp;nbsp;to&amp;nbsp;objects&amp;nbsp;that&amp;nbsp;are&amp;nbsp;created&amp;nbsp;in&amp;nbsp;Heap&amp;nbsp;Space&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 55px;&quot;&gt;All&amp;nbsp;the&amp;nbsp;newly&amp;nbsp;created&amp;nbsp;objects&amp;nbsp;are&amp;nbsp;stored&amp;nbsp;here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 92px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 92px;&quot;&gt;Order&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 92px;&quot;&gt;It's&amp;nbsp;accessed&amp;nbsp;using&amp;nbsp;Last-in&amp;nbsp;First-out&amp;nbsp;(LIFO)&amp;nbsp;memory&amp;nbsp;allocation&amp;nbsp;system&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 92px;&quot;&gt;This&amp;nbsp;memory&amp;nbsp;is&amp;nbsp;accessed&amp;nbsp;via&amp;nbsp;complex&amp;nbsp;memory&amp;nbsp;management&amp;nbsp;techniques&amp;nbsp;that&amp;nbsp;include&amp;nbsp;Young&amp;nbsp;Generation,&amp;nbsp;Old&amp;nbsp;or&amp;nbsp;Tenured&amp;nbsp;Generation,&amp;nbsp;and&amp;nbsp;Permanent&amp;nbsp;Generation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 37px;&quot;&gt;Life&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 37px;&quot;&gt;Stack&amp;nbsp;memory&amp;nbsp;only&amp;nbsp;exists&amp;nbsp;as&amp;nbsp;long&amp;nbsp;as&amp;nbsp;the&amp;nbsp;current&amp;nbsp;method&amp;nbsp;is&amp;nbsp;running&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 37px;&quot;&gt;Heap&amp;nbsp;space&amp;nbsp;exists&amp;nbsp;as&amp;nbsp;long&amp;nbsp;as&amp;nbsp;the&amp;nbsp;application&amp;nbsp;runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 37px;&quot;&gt;Efficiency&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 37px;&quot;&gt;Much&amp;nbsp;faster&amp;nbsp;to&amp;nbsp;allocate&amp;nbsp;when&amp;nbsp;compared&amp;nbsp;to&amp;nbsp;heap&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 37px;&quot;&gt;Slower&amp;nbsp;to&amp;nbsp;allocate&amp;nbsp;when&amp;nbsp;compared&amp;nbsp;to&amp;nbsp;stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 74px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 74px;&quot;&gt;Allocation/Deallocation&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 74px;&quot;&gt;This&amp;nbsp;Memory&amp;nbsp;is&amp;nbsp;automatically&amp;nbsp;allocated&amp;nbsp;and&amp;nbsp;deallocated&amp;nbsp;when&amp;nbsp;a&amp;nbsp;method&amp;nbsp;is&amp;nbsp;called&amp;nbsp;and&amp;nbsp;returned,&amp;nbsp;respectively&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 74px;&quot;&gt;Heap&amp;nbsp;space&amp;nbsp;is&amp;nbsp;allocated&amp;nbsp;when&amp;nbsp;new&amp;nbsp;objects&amp;nbsp;are&amp;nbsp;created&amp;nbsp;and&amp;nbsp;deallocated&amp;nbsp;by&amp;nbsp;Gargabe&amp;nbsp;Collector&amp;nbsp;when&amp;nbsp;they're&amp;nbsp;no&amp;nbsp;longer&amp;nbsp;referenced&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 마무리하면서 (Conclusion)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;스택과 힙은 Java가 메모리를 할당하는 두 가지 방법입니다. &lt;a href=&quot;https://www.baeldung.com/java-memory-management-interview-questions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 글&lt;/a&gt;에서는 작동 방식과 더 나은 Java 프로그램 개발을 위해 사용하는 경우를 배웠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Java의 메모리 관리에 대해 자세히 알아보려면 여기에서 &lt;a href=&quot;https://www.baeldung.com/jvm-garbage-collectors&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 글&lt;/a&gt;을 살펴보십시오. 또한 이 문서에서 간략하게 설명하는 JVM Garbage Collector에 대해서도 다루었습니다.&lt;/p&gt;</description>
      <category>Java</category>
      <author>merlin.park</author>
      <guid isPermaLink="true">https://binarycube.tistory.com/8</guid>
      <comments>https://binarycube.tistory.com/8#entry8comment</comments>
      <pubDate>Wed, 18 Jan 2023 13:10:55 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin에서 emptyList와 listOf</title>
      <link>https://binarycube.tistory.com/4</link>
      <description>&lt;p&gt;Kotlin을 개발하다 보면 listOf()와 emptyList()를 자주 사용하게 되는데, 두 함수의 내부가 궁금해졌다. 결론부터 적어보자면, 표현식이 다를 뿐 listOf()와 emptyList()는 Immutable List를 만들어내는 함수들이다. 아래는 이에 대해 알아본 내용이니 시간 있다면 한 번 보는 것도 나쁘지는 않다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;일단 emptyList와 listOf는 모두kotlin.collections 패키지 안에 포함되어있다. Kotlin에서 제공하는 Collection 지원들인데, 그렇다면 어떤 것이 다를까?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;일단 emptyList의 코드는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1583731160561&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * Returns an empty read-only list.  The returned list is serializable (JVM).
 * @sample samples.collections.Collections.Lists.emptyReadOnlyList
 */
public fun &amp;lt;T&amp;gt; emptyList(): List&amp;lt;T&amp;gt; = EmptyList&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;함수 emptyList의 반환값은 EmptyList라는 Object임을 알 수 있다. 그렇다면 EmptyList 오브젝트는 어떤 것일까?&lt;/p&gt;
&lt;pre id=&quot;code_1583731087346&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;internal object EmptyList : List&amp;lt;Nothing&amp;gt;, Serializable, RandomAccess {
    private const val serialVersionUID: Long = -7390468764508069838L
    
    override fun equals(other: Any?): Boolean = other is List&amp;lt;*&amp;gt; &amp;amp;&amp;amp; other.isEmpty()
    override fun hashCode(): Int = 1
    override fun toString(): String = &quot;[]&quot;

    override val size: Int get() = 0
    override fun isEmpty(): Boolean = true
    override fun contains(element: Nothing): Boolean = false
    override fun containsAll(elements: Collection&amp;lt;Nothing&amp;gt;): Boolean = elements.isEmpty()

    override fun get(index: Int): Nothing = throw IndexOutOfBoundsException(&quot;Empty list doesn't contain element at index $index.&quot;)
    override fun indexOf(element: Nothing): Int = -1
    override fun lastIndexOf(element: Nothing): Int = -1

    override fun iterator(): Iterator&amp;lt;Nothing&amp;gt; = EmptyIterator
    override fun listIterator(): ListIterator&amp;lt;Nothing&amp;gt; = EmptyIterator
    override fun listIterator(index: Int): ListIterator&amp;lt;Nothing&amp;gt; {
        if (index != 0) throw IndexOutOfBoundsException(&quot;Index: $index&quot;)
        return EmptyIterator
    }

    override fun subList(fromIndex: Int, toIndex: Int): List&amp;lt;Nothing&amp;gt; {
        if (fromIndex == 0 &amp;amp;&amp;amp; toIndex == 0) return this
        throw IndexOutOfBoundsException(&quot;fromIndex: $fromIndex, toIndex: $toIndex&quot;)
    }

    private fun readResolve(): Any = EmptyList
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결국 내용은 &quot;아무것도 없는 빈 List&quot;와 동일하다. List 인터페이스를 구현하고 있으며, override된 함수들을 모두 보면 비어있는 리스트의 반환 값들을 정적으로 선언해 놓았다. 즉 &quot;비어있는 Immutable List&quot;라고 보면 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그럼 다음으로 listOf()를 확인해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1583731608374&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * Returns an immutable list containing only the specified object [element].
 * The returned list is serializable.
 * @sample samples.collections.Collections.Lists.singletonReadOnlyList
 */
public fun &amp;lt;T&amp;gt; listOf(element: T): List&amp;lt;T&amp;gt; = java.util.Collections.singletonList(element)

/**
 * Returns a new read-only list of given elements.  The returned list is serializable (JVM).
 * @sample samples.collections.Collections.Lists.readOnlyList
 */
public fun &amp;lt;T&amp;gt; listOf(vararg elements: T): List&amp;lt;T&amp;gt; = if (elements.size &amp;gt; 0) elements.asList() else emptyList()

/**
 * Returns an empty read-only list.  The returned list is serializable (JVM).
 * @sample samples.collections.Collections.Lists.emptyReadOnlyList
 */
@kotlin.internal.InlineOnly
public inline fun &amp;lt;T&amp;gt; listOf(): List&amp;lt;T&amp;gt; = emptyList()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;세 가지의 listOf 프로토타입이 있는데, 앞의 두 가지는 전달받은 값을 포함하는 ImmutableList라고 볼 수 있다. 그리고 아래 코드를 보면 아무런 인자도 전달받지 않은 listOf() 함수가 있는데 이 값이 emptyList()를 반환하는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;좀 더 명확하게 빈 리스트를 보여주기 위해서는 emptyList()를 쓰는 것이 코드리뷰와 같은 가독성에 있어서는 괜찮은 컨벤션이 되지 않을까 싶다. listOf()인데 인자가 없는 경우에 대해서는 리뷰 단계에서 누락과 같은 요인을 확인해볼 수도 있을 것 같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;@inlineOnly가 있는 것으로 봐서 결국 listOf()로 작성된 코드는 오버헤드를 줄이기 위해 emptyList()로 치환될 것을 알 수 있다. inline에 대해서도 더 적어볼까 하였는데 내용이 꽤나 많아서 다른 글로 알아보는 것이 좋을 것 같다. 아마도 다음 글이 되지 않을까 싶다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;오랜만에 쓰는 글인데, 앞으로는 꼭 생소하거나 특별해보이는 이슈가 아니더라도 소소하게 이렇게 글을 남겨볼까 한다. 예전에는 검색했을 때 많이 나오는 내용이면 잘 안 쓰게 되었는데 이제는 있는 내용이더라도 찾아본 내용에 대해서는 내 방식대로 생각 정리해보는 게 어떨까 싶다. 그런 의미로 보시는 분이 보기에 글의 정성(?)은 좀 부족할 수 있으나 글을 쓰는 시간 동안의 생각정리에 좀 더 주안점을 두고, 기록 자체에 비중을 둘까 한다.&lt;/p&gt;</description>
      <category>Kotlin</category>
      <author>merlin.park</author>
      <guid isPermaLink="true">https://binarycube.tistory.com/4</guid>
      <comments>https://binarycube.tistory.com/4#entry4comment</comments>
      <pubDate>Mon, 9 Mar 2020 14:40:31 +0900</pubDate>
    </item>
    <item>
      <title>What is difference between MongoDB and Cassandra</title>
      <link>https://binarycube.tistory.com/3</link>
      <description>&lt;p&gt;본 글은&amp;nbsp;해석한 내용이며&amp;nbsp;원문 링크는 하단에 있습니다.&amp;nbsp;&lt;/p&gt;&lt;h2&gt;Cassandra vs. MongoDB&lt;/h2&gt;&lt;p&gt;&amp;nbsp;Cassandra나 MongoDB를 다음 프로젝트의 데이터베이스로 생각하고 있으신가요? 두 데이터베이스를 비교하고 싶으신가요? Cassandra&amp;nbsp;와 MongoDB 모두&amp;nbsp;NoSQL 데이터베이스이지만 사실&amp;nbsp;둘은 매우 다릅니다. 그들은 매우 다른 능력과 방향성을&amp;nbsp;갖고 있으므로&amp;nbsp;미묘한 차이를 갖고 있습니다. 두 데이터베이스 중 어느 것도 RDBMS를 대체하지는 않으며 ACID를 보장하지도 않습니다. 만약 당신이 이러한 트랜잭션 단위의 작업이 주된 요구사항이라면 이러한 데이터베이스는 적합하지 않습니다. 이러한 경우에는&amp;nbsp;MySQL이나 PostgreSQL, Oracle과 같은&amp;nbsp;트랜잭션을 지원하는 관계형 데이터베이스를 사용하는 것이 더 적합합니다. 이제 관계형 데이터베이스는 배제하고 이야기 해봅시다. Cassandra와 MongoDB 간의 주된 차이점을 비교해보는 것이 결정하는데 도움이 될 것입니다. 이 포스팅에서는 결정을 내리는데 도움을 주기 위해서&amp;nbsp;데이터베이스에 대한 구체적인 기능에 대해 논하는 것 대신&amp;nbsp;고차원의 전략적 차이점을&amp;nbsp;논할 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.&amp;nbsp;Expensive Object Model&lt;/h3&gt;&lt;div&gt;&amp;nbsp;MongoDB는 다양한 객체모델(Object Model)을 지원합니다. 객체(Object)는 속성(Property)를 가질 수 있고 객체는 다른 객체를 계층구조로&amp;nbsp;가질 수 있습니다. 이런 모델은 상당히 객체지향적이며 어떠한 객체의 구조라도 표현할 수 있습니다. 또한 계층구조 전반에 대해서 어떠한 속성이라도 인덱스를 설정할 수 있다는 특성이 있으며 매우 큰 장점입니다. 반면 Cassandra의 경우에는 행과 열로 이루어진 기존의 테이블형태를 제공합니다. 데이터는 보다 구조화되고 각각의 컬럼은 테이블을 생성할 때&amp;nbsp;데이터타입이 정의되어야 합니다. 만약 다양한 형태의 데이터모델이 필요하다면 MongoDB가 Cassandra에 비해 적합할 것입니다.&lt;/div&gt;&lt;h3&gt;2. Secondary Indexes&lt;/h3&gt;&lt;div&gt;&amp;nbsp;MongoDB의&amp;nbsp;보조인덱스(Secondary Indexes)는 적재된 객체의 어떠한 속성이라도&amp;nbsp;쉽게 인덱스로 설정할 수 있으며 이를&amp;nbsp;통해서&amp;nbsp;쿼리를 보다 쉽게 질의할 수 있습니다. Cassandra는 보조인덱스에 대해 피상적인 수준으로만 제공할 뿐입니다. 단일 컬럼에 대해서만 설정할 수 있으며 동등비교연산(=)만 가능합니다. 만약 기본키를 주로 사용할 것이라면 Cassandra가 적합할것입니다. 만약 보조인덱스를 필요로 하며 쿼리모델에서 유연성(flexibility)가 요구된다면 MongoDB가 더욱 적합할 것입니다.&lt;/div&gt;&lt;h3&gt;3. High Availability&lt;/h3&gt;&lt;p&gt;&amp;nbsp;MongoDB는 하나의 마스터노드(Master node)와 다수의 슬레이브노드(Slave node)로 구성된&amp;nbsp;&lt;i&gt;Single Master&lt;/i&gt; 모델을 지원합니다. 만약 마스터노드에 장애가 발생한 경우에 슬레이브노드의 하나가 마스터로 설정됩니다. 이러한 과정은 자동으로&amp;nbsp;이뤄지지만 10초에서 40초 가량의 시간이 소요됩니다. 기존의 슬레이브노드가 리더로서 선정되는 동안 다른 쓰기작업을 할 수 없습니다. 대부분의 응용프로그램에게 있어서 이러한 작업이 수행되지만 결국은 사용자에 필요에 의해 결정됩니다. Cassandra는 Multiple master 모델을 지원합니다. 클러스터 중에&amp;nbsp;단일노드가 유실되더라도&amp;nbsp;쓰기작업에 대해 영향을 미치지 않습니다. 그러므로 100% 가용성을 유지할 수 있습니다. 만약 100% 가동시간을 확보하고 싶다면 Cassandra가 더욱 적합할 것입니다.&lt;/p&gt;&lt;h3&gt;4. Write&amp;nbsp;Scalability&lt;/h3&gt;&lt;div&gt;&amp;nbsp;Single master 모델을 차용하고 있는&amp;nbsp;MongoDB는 마스터노드에서만 쓰기작업을 수행할 수 있습니다. 보조서버들은 읽기 작업에만 사용됩니다. 만약 세 개의 노드의 구성으로 되어있다면 마스터는 오직 읽기만 수행할 것이고 나머지 두 개의 노드는 읽기 작업을 수행하게 됩니다. 이러한 구성은 쓰기작업에 제약사항이 됩니다. 여러 샤드를&amp;nbsp;배포를 할 수 있지만 한 개의 데이터노드만이 쓰기작업을 수행할 수 있습니다. Multiple master 모델인&amp;nbsp;Cassandra는 어떠한 노드에서든 쓰기작업을 할 수 있습니다. 쓰기 확장성은 클러스터에 존재하는 서버의 수와 상관이 있습니다. 클러스터에 서버가 많을 수록 쓰기 가용성이 높아질것입니다. 만약 높은 쓰기 확장성이 필요로한다면 Cassandra가 적합할 것입니다.&lt;/div&gt;&lt;h3&gt;5. Query Language Support&lt;/h3&gt;&lt;div&gt;&amp;nbsp;Cassandra는 SQL와 매우 흡사한&amp;nbsp;형태인 CQL를&amp;nbsp;지원합니다. 만약 기존의 데이터분석팀이 있다면&amp;nbsp;SQL 기술들을 이용하여&amp;nbsp;대응할 수 있다는 것은 대규모 데이터를 최적화 하는데 있어서 매우 중요한 부분입니다. 하지만 CQL은 JOIN이나&amp;nbsp;OR절을 지원하지 않는 등&amp;nbsp;ANSI SQL을 모두 지원하지는 않고 몇 가지 제약사항이 존재합니다. MongoDB는 이러한 부분에 대해&amp;nbsp;쿼리문에 대한 지원을 하지 않습니다. 쿼리는 JSON으로 구성되어있습니다. 만약 쿼리문을 지원하길 바란다면 Cassandra가 더욱 적합할 것입니다.&lt;/div&gt;&lt;h3&gt;6. Performance Benchmarks&lt;/h3&gt;&lt;div&gt;&amp;nbsp;성능에 대해서 이야기해봅시다. 이 부분에서&amp;nbsp;데이터베이스의 비교를 기대하겠지만 의도적으로 이러한 부분을 포함하지 않았습니다. 어떠한 비교에서든 apples-to-apples 비교라는 것을&amp;nbsp;충분히 인지해야합니다.&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Database Model&lt;/b&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&amp;nbsp;- 데이터베이스의 모델이나 스키마가 가장 큰 차이를 만드는 것으로&amp;nbsp;테스트 되었습니다. 어떠한 스키마는 MongoDB에 적합하였고 또 다른 것은 Cassandra에 적합하였습니다. 우리가 데이터베이스를 비교할때 각각의 데이터베이스에 합리적으로 작동하도록 모델을 적용하는 것이&amp;nbsp;매우 중요합니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Load characteristic&lt;/b&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt; - 벤치마크 부하의 형질이 매우 중요합니다. 예를 들어 쓰기에 비중을 둔 벤치마크라면 Cassandra가 MongoDB보다 앞설것이며, 읽기에 비중을 둔 테스트라면 MongoDB와 Cassandra가 비슷한 성능을 낼것입니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Consistency requirements&lt;/b&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&amp;nbsp;- 이 것은 꽤나 까다로운 문제입니다. 당신이 읽기/쓰기의 일관성이 두 데이터베이스에 동일하여 다른 한 쪽에 편향되지 않도록 주의해아합니다. 매우 많은 마케팅 벤치마크에서는 다른 쪽을 불리하게 조정합니다. 그러므로 일관성을 조정하는데 주의를 기울여야 할 것입니다.&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;마지막으로 유념해야할 것은 성능테스트가&amp;nbsp;당신의 프로그램의 형질을 반영하지 않았을 수 있다는 것입니다. 그러므로 성능측정이 무의미해지지 않기 위해서 당신의 프로그램의 형질을 제대로 반영했는지 여부를 확인하는 것이 매우 중요한 일입니다.&amp;nbsp;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;7. Ease of Use&lt;/h3&gt;&lt;div&gt;&amp;nbsp;만약 이러한 질문을 몇 넌 전에 했다면 MongoDB가 승자였을것입니다. MongoDB를 구동하고 운영하는 것은 꽤나 간단한 작업이기 때문입니다. 하지만 지난 몇년동안 Cassandra는 이 부분에 있어서 상품으로서 괄목할만한 성장을 했습니다. Cassandra에 기본 인터페이스로서 CQL을 도입하므로서 더욱 개선되었고 SQL 프로그래머들이 Cassandra를 쉽게 사용할 수 있도록 하였습니다.&lt;/div&gt;&lt;h3&gt;8.&amp;nbsp;Native Aggregation&lt;/h3&gt;&lt;div&gt;&amp;nbsp;MongoDB는 데이터베이스에 적재된 데이터를 변형할 수 있도록 ETL 파이프라인을 구동할 수 있는 자체 집합 프레임워크(Aggregation framework)를 제공합니다. 이는 중-소규모 작업에서 효과적이지만 당신의 데이터의 복잡도와 규모가 커질수록 디버깅하기 더욱 어려워집니다. Cassandra는 이러한 툴을 제공하지 않으며 Hadoop이나 Spark와 같은 외부 툴을 이러한 목적을 위해 이용할 수 있습니다.&lt;/div&gt;&lt;h3&gt;9. Schema-less Model&lt;/h3&gt;&lt;p&gt;&amp;nbsp;MongoDB에서 당신은 도큐먼트(Document)에 어떠한 스키마도 강제하지 않도록 설정할 수 있습니다. 이전 버전에서는 이것이 기본설정이었지만 새로운 버전에서는 도큐먼트에 스키마를 강제하도록 하는 옵션을 설정할 수 있게 되었습니다. MongoDB에서의&amp;nbsp;각 도큐먼트는 다른 구조를 가질 수 있었고 이를 해석하여 사용하는 일은 어플리케이션에 달려있습니다. 이러한 경우는 대부분의 어플리케이션에서 적절하지 않지만 유연성이 필요한&amp;nbsp;특정 케이스에서는 중요합니다. CQL을 기본 언어로 하는&amp;nbsp;새로운 버전의 Cassandra에서는 정적타입(static typing)을 지원합니다. 당신은 컬럼의 타입을 사전에 정의해아합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;* 모든 오역은 피드백 주시면 반영하도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;원문 :&amp;nbsp;&lt;a href=&quot;https://scalegrid.io/blog/cassandra-vs-mongodb/&quot;&gt;https://scalegrid.io/blog/cassandra-vs-mongodb/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Database</category>
      <author>merlin.park</author>
      <guid isPermaLink="true">https://binarycube.tistory.com/3</guid>
      <comments>https://binarycube.tistory.com/3#entry3comment</comments>
      <pubDate>Fri, 24 Nov 2017 16:05:08 +0900</pubDate>
    </item>
    <item>
      <title>웹소켓 포트포워딩 | WebSocket Proxy : proxy_wstunnel</title>
      <link>https://binarycube.tistory.com/2</link>
      <description>&lt;p&gt;Atlassian의 Confluence를 세팅하는데 에디터 부분에서 자꾸 에러가 났다. 개발자 콘솔로 뜯어본 결과&amp;nbsp;통신형태에서 http 프로토콜 뿐만 아니라 websocket도 병행적으로 요청이 일어났으며 데이터 동기화를 유지하도록 하는 것이 목적인듯 보였다. Confluence는 기본적으로 8090번 포트를 사용하는데 http뿐만 아니라 websocket의 경우도 Apache의 Reverse Proxy기능을 이용하여 80에서 8090으로 포워딩이 필요했다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;결론부터 말하자면 proxy_wstunnel 뿐만 아니라 rewirte 모듈도 필요한 케이스였다. (ProxyPass로는 별 짓을 다 해봤는데 못찾은건지 몰라라도 안됐음) Web Socket 요청이 들어갈 때 Http Request Header에 &lt;i&gt;Connection: Upgrade&lt;/i&gt; 라는 헤더가 들어가게 되는데 해당 경우가 websocket일 경우에 직접적으로 Redirect 시켜주는 부분이 필요했다. 그리고 그 이외의 경우에는 단순하게 ProxyPass를 통해서 했던거와 마찬가지로 http 프로토콜을 이용하여 포워딩 시켜주면 되는 형태였다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code value=&quot;perl&quot;&gt;
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule rewrite_module modules/mod_rewrite.so

&amp;lt;Virtualhost *:80&amp;gt;
	ProxyPreserveHost On
	ProxyRequests Off
	
	ServerAdmin admin@mydomain.com
	ServerName confluence.mydomain.com
	
	RewriteEngine On
	RewriteCond %{HTTP:Upgrade} =websocket [NC]
	RewriteRule /(.*\/websocket) ws://localhost:8090/$1 [P,L]
	RewriteCond %{HTTP:Upgrade} !=websocket [NC]
	RewriteRule /(.*) http://localhost:8090/$1 [P,L]

#	ProxyPass / http://localhost:8090/
	ProxyPassReverse / http://localhost:8090/

	KeepAlive On
	ErrorLog ${APACHE_LOG_DIR}/confluence-error.log
	CustomLog ${APACHE_LOG_DIR}/confluence-access.log combined

&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;몇 가지 세부적인 세팅에 대해 각자 다르겠지만 큰 골자는 이와 같다. 예전에 한창 PHP 개발을 시작했을 때 .htaccess 파일로 index.php나 정적 파일 경로를 은닉시키려고 Rewrite 모듈을 공부했는데 너무 오랜만에 하니 잘 모르겠기도 하다. 오늘 반나절가량 이거로 삽질하면서 다시 한 번 Apache Rewrite 모듈에 대해 공부해야할 필요성을 느꼈다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;참고로 proxy_wstunnel의 경우는 Apache 2.4 이상 버전에서 지원하는 모듈이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;참고 :&amp;nbsp;&lt;a href=&quot;http://stackoverflow.com/questions/27526281/websockets-and-apache-proxy-how-to-configure-mod-proxy-wstunnel&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://stackoverflow.com/questions/27526281/websockets-and-apache-proxy-how-to-configure-mod-proxy-wstunnel&lt;/a&gt;&lt;/p&gt;</description>
      <category>Apache</category>
      <author>merlin.park</author>
      <guid isPermaLink="true">https://binarycube.tistory.com/2</guid>
      <comments>https://binarycube.tistory.com/2#entry2comment</comments>
      <pubDate>Tue, 13 Dec 2016 01:31:11 +0900</pubDate>
    </item>
    <item>
      <title>JPA에서 순환참조를 해결하는 방법 | @JsonIgnore, @JsonManagedReference, @JsonBackReference</title>
      <link>https://binarycube.tistory.com/1</link>
      <description>&lt;p&gt;&amp;nbsp;JPA는 ORM이기 때문에 RDB를 관리하는데 있어서 양방향 참조를 필요로 한다. 물론 필수는 아니지만 Entity는 본질적인 데이터를 표현하는 것이기 때문에 그 관계에 대하여 명세해주는 것이 원칙이라고&amp;nbsp;생각한다. (이에 대해 별개로 처리하는 부분이 있다면 DTO를 통하는 방법이 맞다고 생각한다.)&amp;nbsp;이러한 양방향 참조로 인해서 RESTFul API 서버를 구현하는데 있어서 문제가 생겼는데 바로 응답에 Entity를 담아서 보낼 경우에 JsonSerializer가&amp;nbsp;toString()을 호출할 때 property들을&amp;nbsp;매핑하는 과정에서 무한 순환 참조가 일어나게 되는 문제이다. 예를 들어 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;
public class Article {
    @Id
    private long id;
    // ...
    @OneToMany(mappedBy = &quot;article&quot;, fetch = FetchType.LAZY)
    private List&lt;comment&gt; comments;
}

public class Comment {
    @Id
    private long id;
    // ...
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColum(name = &quot;article_id&quot;)
    @LazyToOne(value = LazyToOneOption.NO_PROXY)
    private Article article;
}&lt;/comment&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;위와 같은 형태로 글(Article)은 다수의 댓글(Comment)객체를 갖고 있고 댓글의 경우 그 반대이다. RDB의 특성상 이 관계의 참조의 키가 되는 article_id는 comment 테이블이 갖고 있는 형태이나 ORM의 특성상 이러한 관계를 양쪽 클래스&amp;nbsp;모두에 정의하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;이 상태에서 Article 클래스의 toString()을 호출하게 되면 LazyFetch라고 하더라도 모든 클래스의 property를 순회하게 되며, 이 때 comments를 조회하게 되고&amp;nbsp;Hibernate(혹은 다른 JPA 구현체)는 데이터베이스에 질의하고 데이터를 가져온다. 이 때 Article.getcomments() -&amp;gt; Comment.getArticle() -&amp;gt; Article.getComments() -&amp;gt; ... 와 같이 객체가 서로를 무한으로 호출하게 되는 문제가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;이러한 문제를 해결하는 방법으로 @JsonIgnore를 사용하는 방법이 있고 @JsonManagedReference와 @JsonBackReference를 사용하는 방법이 있다. 표면적으로 두 방법 모두 순환참조를 방어하는 형태이지만 본질적으로 약간의 차이가 있다. @JsonIgnore의 경우는 실제로 property에 null을 할당하는 방식이고 @JsonManagedReference와 @JsonBackReference는 본질적으로 순환참조를 방어하기 위한 Annotation이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;정리를 하자면 json serialize 과정에서 null로 세팅하고자 하면 @JsonIgnore 사용하면 되고, 순환참조에 대한 문제를 해결하고자 한다면 부모 클래스측에 @JsonManagedReference를, 자식측에 @JsonBackReference를 Annotation에 추가해주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;기본적으로 DTO와 같이 별도의 전달 객체를 활용하여 Mapper를 이용한다면 위와 같은 문제가 없겠지만 경우에 따라 필요한 옵션이 있을 수 있어 찾아보았다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;참조&amp;nbsp;:&amp;nbsp;&lt;a href=&quot;http://stackoverflow.com/a/37393711&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://stackoverflow.com/a/37393711&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>JPA</category>
      <author>merlin.park</author>
      <guid isPermaLink="true">https://binarycube.tistory.com/1</guid>
      <comments>https://binarycube.tistory.com/1#entry1comment</comments>
      <pubDate>Sun, 11 Dec 2016 15:36:30 +0900</pubDate>
    </item>
  </channel>
</rss>