<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>icedstone 님의 블로그</title>
    <link>https://icedstone.tistory.com/</link>
    <description>읽기 귀찮지 않게 짧게 많이 쓰는걸 목표로 하기</description>
    <language>ko</language>
    <pubDate>Sun, 12 Apr 2026 11:48:30 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>icedstone</managingEditor>
    <image>
      <title>icedstone 님의 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/7748490/attach/5d2c8f23cf8b4e4a919faf2b99fd33b5</url>
      <link>https://icedstone.tistory.com</link>
    </image>
    <item>
      <title>Kubernetes OOM 원인: JVM MaxRAMPercentage</title>
      <link>https://icedstone.tistory.com/16</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;상황 설명&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 중인 Kubernetes 환경에서 Pod가 주기적으로 **&lt;b&gt;OOMKilled&lt;/b&gt;(Out Of Memory)**로 인해 재시작되는 현상이 발생.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론 먼저&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하고 있던 jvm의 버그&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; jdk 1.8(432) 버전 사용 중이었는데 k8s 환경에서 MaxRAMPercentage 옵션 사용시 Pod가 아닌 Node 메모리를 기준으로 하는 버그가 존재 &lt;i&gt;(찾아보면 jdk 1.8(372)에서 해결된 버그라고 나오지만 실제 테스트 해보면 그렇지 않았다)&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;확인 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;여러가지 삽질했던 기록은 생략&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Pod 터미널에 들어가서 JVM 메모리 설정 확인&lt;/p&gt;
&lt;pre id=&quot;code_1771385047532&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;jcmd {pid} VM.flags&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령어 실행시 jvm 설정 정보들이 나온다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;..... &lt;b&gt;-XX:MaxHeapSize=6092226560&lt;/b&gt; .....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약 6GB 로 Pod의 메모리로 설정되어있던 2GB 보다 훨씬 큰 값으로 잡혀있다.&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;MaxRAMPercentage=75 으로 사용 중이었는데 Pod가 아닌 메모리를 기준으로 70%를 가져오고 있다는 의미다.&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;2. Kubernetes Node 메모리를 확인&lt;/p&gt;
&lt;pre id=&quot;code_1771385491574&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl get nodes -o custom-columns=NAME:.metadata.name,MEMORY:.status.capacity.memory&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node 메모리 확인시 약 8GB &lt;i&gt;(8 * 0.75 = 6)&lt;/i&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node의 메모리를 기준으로 75%를 해서 JVM MaxHeapSize가 설정되었음을 확인할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MaxRAMPercentage&lt;/b&gt;설정 대신 &lt;b&gt;Xmx&lt;/b&gt; 로 고정값으로 메모리 설정하도록 수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;b&gt;InitialRAMPercentage&lt;/b&gt;도 사용하고 있어서 해당 설정은 &lt;b&gt;Xms&lt;/b&gt;로 수정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 이슈 찾아보면 kubernetes의 cgroup v2를 사용할 때 있던 버그라고 한다. 실제 사용하고 있는 환경도 확인해봤을 때 cgroup v2를 사용하고 있었다.&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;cgroup 버전은 아래 명령어 하위에 있는 경로로 확인이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1771386465224&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ls -l /sys/fs/cgroup/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;v2:&lt;/b&gt; cgroup.controllers 파일이 존재함. (단일 계층 구조)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,0&quot;&gt;v1:&lt;/b&gt; cpu, memory, blkio 등 리소스별 디렉터리가 분리되어 존재함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;확인하면서 참고했던 글&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.leeby.one/posts/JVM-Container-Awareness-Bug-cgroup-v2-JDK-11.0.16/&quot;&gt;- https://www.leeby.one/posts/JVM-Container-Awareness-Bug-cgroup-v2-JDK-11.0.16/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.redhat.com/articles/2023/04/19/openjdk-8u372-feature-cgroup-v2-support#openjdk_8u362_and_older__cgroup_v1_only&quot;&gt;- https://developers.redhat.com/articles/2023/04/19/openjdk-8u372-feature-cgroup-v2-support#openjdk_8u362_and_older__cgroup_v1_only&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://stackoverflow.com/questions/58119322/openjdk-maxrampercentage-on-a-machine-with-very-large-amount-of-memory&quot;&gt;https://stackoverflow.com/questions/58119322/openjdk-maxrampercentage-on-a-machine-with-very-large-amount-of-memory&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://findstar.pe.kr/2022/07/10/java-application-memory-size-on-container/&quot;&gt;https://findstar.pe.kr/2022/07/10/java-application-memory-size-on-container/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Troubleshooting</category>
      <category>k8s</category>
      <category>maxrampercentage</category>
      <category>OOM</category>
      <category>oomkilled</category>
      <category>pod</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/16</guid>
      <comments>https://icedstone.tistory.com/16#entry16comment</comments>
      <pubDate>Wed, 18 Feb 2026 12:49:02 +0900</pubDate>
    </item>
    <item>
      <title>Java Collection - List</title>
      <link>https://icedstone.tistory.com/15</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;가장 자주 비교되는 ArrayList와 LinkedList 그리고 Array하고는 어떻게 다른지 확인해보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList의 경우 실제 내부에 Array구조를 가져가고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1754615356132&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ArrayList&amp;lt;E&amp;gt; {
    Object[] data;
    
    E get(int index) {
      return (E) data[index];
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 ArrayList도 내부적으로 Array형태를 가져가고 있지만, 핵심은 동적인 리사이징 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Array의 경우 최초에 선언한 사이즈에서 조절이 불가능하다. ArrayList의 경우 초기 설정한 size보다 더 많은 양의 데이터가 들어올 경우 자동으로 사이즈를 조절하여 새로운 배열에 데이터가 쌓인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 ArrayList에 무작정 데이터를 적재하면 어떻게 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 사이즈는 기본값 10으로 시작한다. 그리고 데이터가 초과될 때 마다 1.5배로 사이즈를 확장한다. 10 -&amp;gt; 15 -&amp;gt; 22 이렇게 사이즈가 커지고 당연히 여기서는 그만큼의 성능을 요구한다.(만약 사이즈가 변경되는 시점에 같이 사용하는 Thread가 있다면 동시성 문제 또한 있을 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 사이즈가 얼마큼 커질지 알고 있다면 당연히 사이즈를 지정해서 선언하는것이 유리하다.&lt;/p&gt;
&lt;pre id=&quot;code_1754616270114&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; list = new ArrayList(255);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 비해서 LinkedList의 경우에는 아래와 같이 이중 연결 리스트 구조로 되어있다.&lt;/p&gt;
&lt;pre id=&quot;code_1754616567395&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class LinkedList&amp;lt;E&amp;gt; {
    Node&amp;lt;E&amp;gt; first;
    Node&amp;lt;E&amp;gt; last;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 탐색을 할 경우 시작부터 index위치까지 순회해야한다(O(n)). 대신 삽입/삭제가 빈번한 경우 다음 Node의 포인터만 변경해주면 되기 때문에, 중간 위치에 있는 데이터도 빠른 변경이 가능하다. 만약 데이터가 많고 삽입/삭제가 빈번하다면 ArrayList 보다 유리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>ArrayList</category>
      <category>collection</category>
      <category>Java</category>
      <category>LinkedList</category>
      <category>list</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/15</guid>
      <comments>https://icedstone.tistory.com/15#entry15comment</comments>
      <pubDate>Fri, 8 Aug 2025 10:37:21 +0900</pubDate>
    </item>
    <item>
      <title>Java Collection - Map</title>
      <link>https://icedstone.tistory.com/14</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;아마 가장 많이 사용하는 Map은 HashMap일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HashMap의 구조에 대해서 살펴보자&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;HashMap key값에서 value를 찾을 수 있는 O(1) 형태의 데이터 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 모든 객체는 hashCode()와 equals() 메소드를 가지고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1752996618431&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node&amp;lt;K,List&amp;lt;V&amp;gt;&amp;gt;[] table;

public V get(Object key) {
	int index = object.hashCode() % 16;
	List&amp;lt;V&amp;gt; list = table[index];
    for(int i = 0; i &amp;lt; list.size(); i++) {
      if(list.get(i).equals(key))
      	return list.get(i);
    }
    return null;
}
// 설명을 위해 단순화된 예시, 실제로는 훨씬 복잡하다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 hashCode()를 통해 index의 위치를 탐색하기 때문에 O(1) 형태의 구조를 가지지만 hash충돌이 많을 경우 O(n)의 구조를 가져갈 수 있으니 hashCode(), equals()를 재구현해야할 경우 주의가 필요하다.&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;또한 위에서는 List로 설명하였는데, jdk 1.8부터는 Tree구조를 가져가고 있으니 hash 충돌에도 더 빠른 탐색(O(log n))이 가능하다.(초기에는 List로 저장하다가 충돌이 많아지면 Tree로 변환해서 저장한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외에도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키 순서가 정렬되어있는 TreeMap&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 순서(or 접근 순서)가 보장되는 LinkedHashMap&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시성이 보장되는 ConcurrentHashMap&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키 값이 enum인 경우 최적화 되어있는 EnumMap&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와 같이 다양한 Map 종류를 jdk에서 제공하고 있다.&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>collection</category>
      <category>HashMap</category>
      <category>Java</category>
      <category>map</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/14</guid>
      <comments>https://icedstone.tistory.com/14#entry14comment</comments>
      <pubDate>Fri, 8 Aug 2025 09:37:32 +0900</pubDate>
    </item>
    <item>
      <title>Java IO vs NIO</title>
      <link>https://icedstone.tistory.com/13</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;java.io, java.nio (new input/output)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;io는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;blocking&lt;/span&gt;&lt;/b&gt;, nio 는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;non-blocking&lt;/span&gt;&lt;/b&gt; 방식(blocking도 지원)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;io는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;stream&lt;/b&gt;&lt;/span&gt; 형식으로 입출력, nio는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;channel&lt;/b&gt; &lt;/span&gt;형식으로 입출력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이라고 하지만 결국에는 커넥션을 맺는건데 이게 왜 중요할까???&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 이렇게 생각할 수 있을거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;실제로 데이터를 끊어서 읽어온다음 처리하는게 아니라 다 읽어오고 나서 처리하는건데 non-blocking 되는게 필요한거야?&quot;(물론 끊어 읽어와서 처리하는 것도 가능은하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 의문은 소스코드를 보면 더 커진다.&lt;/p&gt;
&lt;pre id=&quot;code_1745582196352&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;InputStream in = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = in.read(buffer); // 데이터가 들어올 때까지 대기 (blocking)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745582215465&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int bytesRead = socketChannel.read(buffer); // 데이터 없으면 0 반환&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그치만 데이터가 들어올 때 까지 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;blocking&amp;nbsp;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;된다는 것은 thread가 다른 일을 하지 못한다는 것을 의미한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉 열개의 데이터가 동시에 들어올 때 하나의 thread만이 일한다고 생각하면, 하나씩 열번 처리 되는 것과 하나가 열개를 왔다갔다 하면서 처리하는 정도의 차이가 생길 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 다음 상황을 고려해서 io와 nio중 결정하면 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 연결되는 connection이 많은가?&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>
      <category>JAVA</category>
      <category>blocking</category>
      <category>IO</category>
      <category>Java</category>
      <category>nio</category>
      <category>Non-Blocking</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/13</guid>
      <comments>https://icedstone.tistory.com/13#entry13comment</comments>
      <pubDate>Sun, 20 Jul 2025 15:47:41 +0900</pubDate>
    </item>
    <item>
      <title>Java Collection Framework</title>
      <link>https://icedstone.tistory.com/12</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;A collection is simply an object that groups multiple elements into a single unit. Collections are used to store, retrieve, manipulate, and communicate aggregate data.&lt;br /&gt;&amp;mdash; Collections Framework Overview, Java SE&amp;nbsp;8&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle JDK에서는 Collection에 대해서 데이터를 저장하고 조작하는 표준화된 방식을 제공하고 있다고 설명하고 있다.&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;Collection Framework를 제공함으로써 다음과 같은 이점을 가질 수 있다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 프로그래밍 작업을 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 성능을 향상시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 관련 없는 API간 상호운용성을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. API 학습 비용을 줄인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 더 쉽게 API를 설계, 구현할 수 있게 도와준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 재사용성을 늘린다.&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;Collection Framework 에서 제공하는 Interface는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 그런지 살펴보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 프로그래밍 작업을 줄일 수 있다. &lt;/b&gt;- 배열내에서 사용할 만한 기능들을 이미 구현해두었기에 별도로 구현하지 않아도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752233557068&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String[] names = new String[10];
int size = 0;

void add(String name) {
    names[size++] = name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1752304659667&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;&amp;gt;();
names.add(&quot;Alice&quot;);
names.add(&quot;Bob&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 성능을 향상시킨다.&lt;/b&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;&amp;nbsp; &amp;nbsp;ex: 중간의 원소를 수정할 일이 많은 경우 - LinkedList사용, 임의의 위치에 원소를 찾아야하는 경우가 많은 경우 - ArrayList사용&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;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 관련 없는 API간 상호운용성을 제공한다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752305454329&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set&amp;lt;String&amp;gt; keywordSet = new HashSet&amp;lt;&amp;gt;();
keywordSet.add(&quot;java&quot;);
keywordSet.add(&quot;collections&quot;);

List&amp;lt;String&amp;gt; keywords = new ArrayList&amp;lt;&amp;gt;(keywordSet); // 쉽게 변환 가능
someApi.acceptKeywords(keywords);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. API 학습 비용을 줄인다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- interface기반으로 구현되어있기에, 학습된 기능은 다른 구현체에서도 쉽게 익혀서 사용이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ex: contains method의 경우 List, Set 어디에서든 원소의 존재 여부를 확인하는 method이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 더 쉽게 API를 설계, 구현할 수 있게 도와준다. &lt;/b&gt;- interface형태이기 때문에 구현체에 신경쓰지 않고 유연한 설계 가능&lt;/p&gt;
&lt;pre id=&quot;code_1752305714379&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void printUsers(List&amp;lt;User&amp;gt; users) {
    for (User user : users) {
        System.out.println(user.getName());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 재사용성을 늘린다.&lt;/b&gt; - 이미 구현된 알고리즘이 많아 재사용하여 활용 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1752306019695&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; scores = Arrays.asList(90, 70, 80, 100);
Collections.sort(scores);  // 재사용 가능한 정렬 알고리즘

int idx = Collections.binarySearch(scores, 80);  // 검색도 가능&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Collections에서 제공하는 Interface&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ChatGPT Image Jul 12, 2025, 05_02_50 PM.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRMyAN/btsPfvcHSu9/fkCgWXk4UesKUxogpnqFKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRMyAN/btsPfvcHSu9/fkCgWXk4UesKUxogpnqFKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRMyAN/btsPfvcHSu9/fkCgWXk4UesKUxogpnqFKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRMyAN%2FbtsPfvcHSu9%2FfkCgWXk4UesKUxogpnqFKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;740&quot; height=&quot;493&quot; data-filename=&quot;ChatGPT Image Jul 12, 2025, 05_02_50 PM.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* Map은 Collection interface를 상속하지 않고 별도의 interface로 기능을 제공한다.&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;Map관련 자료: &lt;a href=&quot;https://icedstone.tistory.com/14&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://icedstone.tistory.com/14&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List관련 자료: &lt;a href=&quot;https://icedstone.tistory.com/15&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://icedstone.tistory.com/15&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>Collections</category>
      <category>Java</category>
      <category>list</category>
      <category>map</category>
      <category>Set</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/12</guid>
      <comments>https://icedstone.tistory.com/12#entry12comment</comments>
      <pubDate>Sat, 12 Jul 2025 17:05:22 +0900</pubDate>
    </item>
    <item>
      <title>interface vs abstract class</title>
      <link>https://icedstone.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html?utm_source=chatgpt.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oracle java tutorial&lt;/a&gt; 확인시 다음과 같이 설명하고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Consider using abstract classes if any of these statements apply to your situation:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;You want to share code among several closely related classes.&lt;/li&gt;
&lt;li&gt;You expect that classes that extend your abstract class have many common methods or fields, or require access modifiers other than public (such as protected and private).&lt;/li&gt;
&lt;li&gt;You want to declare non-static or non-final fields. This enables you to define methods that can access and modify the state of the object to which they belong.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Consider using interfaces if any of these statements apply to your situation:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;You expect that unrelated classes would implement your interface. For example, the interfaces&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #09569d;&quot; href=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html&quot;&gt;Comparable&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #09569d;&quot; href=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/Cloneable.html&quot;&gt;Cloneable&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;are implemented by many unrelated classes.&lt;/li&gt;
&lt;li&gt;You want to specify the behavior of a particular data type, but not concerned about who implements its behavior.&lt;/li&gt;
&lt;li&gt;You want to take advantage of multiple inheritance of type.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태/공통 기능이 필요한 경우에는 abstract class&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능 계약, 다중 구현이 필요한 경우에는 interface&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 사용하면 된다는 의미 같은데 여전히 잘 모르겠다. Stack over flow에 나와있는 내용을 보면 다음과 같이 생각하면 쉽다고 한다.&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;할 수 있는 기능을 정의: interface&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 종류의 class: abstract class&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여전히 모르겠다. 구성도로 살펴보자.&lt;/p&gt;
&lt;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-origin-width=&quot;746&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sXNI9/btsO5MyCrgN/d1XMlYaJxehKYVXNzSADe0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sXNI9/btsO5MyCrgN/d1XMlYaJxehKYVXNzSADe0/img.jpg&quot; data-alt=&quot;출처: http://xyzcode.blogspot.com/2016/04/use-abstract-classes-and-interfaces.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sXNI9/btsO5MyCrgN/d1XMlYaJxehKYVXNzSADe0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsXNI9%2FbtsO5MyCrgN%2Fd1XMlYaJxehKYVXNzSADe0%2Fimg.jpg&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;607&quot; height=&quot;292&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: http://xyzcode.blogspot.com/2016/04/use-abstract-classes-and-interfaces.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새(Bird)는 날 수 있는 (Flyable) 동물(Animal) 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항공기(Aircraft)는 날 수 있는 (Flyable) 탈 것(Vehicle)이다.&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;</description>
      <category>JAVA</category>
      <category>abstract class</category>
      <category>Interface</category>
      <category>Java</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/11</guid>
      <comments>https://icedstone.tistory.com/11#entry11comment</comments>
      <pubDate>Sat, 5 Jul 2025 14:43:22 +0900</pubDate>
    </item>
    <item>
      <title>Blocking vs Non-Blocking, Synchronous vs Asynchronous</title>
      <link>https://icedstone.tistory.com/10</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;&lt;/p&gt;
&lt;table style=&quot;color: #000000; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;717&quot; data-start=&quot;342&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;Blocking&lt;/td&gt;
&lt;td&gt;Non-Blocking&lt;/td&gt;
&lt;td&gt;Synchronous&lt;/td&gt;
&lt;td&gt;Asynchronous&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;566&quot; data-start=&quot;469&quot;&gt;
&lt;td data-end=&quot;474&quot; data-start=&quot;469&quot;&gt;의미&lt;/td&gt;
&lt;td data-end=&quot;495&quot; data-start=&quot;474&quot;&gt;요청이 끝날 때까지&amp;nbsp;&lt;b&gt;기다림&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;516&quot; data-start=&quot;495&quot;&gt;요청하고 바로&amp;nbsp;&lt;b&gt;제어권 반환&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;538&quot; data-start=&quot;516&quot;&gt;호출자가 결과를&amp;nbsp;&lt;b&gt;직접 기다림&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;566&quot; data-start=&quot;538&quot;&gt;호출 후 결과는&amp;nbsp;&lt;b&gt;콜백/이벤트로 전달됨&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;654&quot; data-start=&quot;567&quot;&gt;
&lt;td data-end=&quot;572&quot; data-start=&quot;567&quot;&gt;예시&lt;/td&gt;
&lt;td data-end=&quot;588&quot; data-start=&quot;572&quot;&gt;파일 읽기 완료까지 멈춤&lt;/td&gt;
&lt;td data-end=&quot;605&quot; data-start=&quot;588&quot;&gt;읽을 게 없으면 즉시 리턴&lt;/td&gt;
&lt;td data-end=&quot;627&quot; data-start=&quot;605&quot;&gt;A &amp;rarr; B &amp;rarr; 결과 기다림 &amp;rarr; 다음&lt;/td&gt;
&lt;td data-end=&quot;654&quot; data-start=&quot;627&quot;&gt;A &amp;rarr; B 호출만 하고 &amp;rarr; 다음 코드 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;717&quot; data-start=&quot;655&quot;&gt;
&lt;td data-end=&quot;663&quot; data-start=&quot;655&quot;&gt;대표 상황&lt;/td&gt;
&lt;td data-end=&quot;671&quot; data-start=&quot;663&quot;&gt;전통 IO&lt;/td&gt;
&lt;td data-end=&quot;677&quot; data-start=&quot;671&quot;&gt;NIO&lt;/td&gt;
&lt;td data-end=&quot;688&quot; data-start=&quot;677&quot;&gt;일반 함수 호출&lt;/td&gt;
&lt;td data-end=&quot;717&quot; data-start=&quot;688&quot;&gt;Future, Callback, Reactor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 비교가 어렵다면 다음과 같이 비교해보도록 하자&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Blocking vs Non-Blocking&lt;/b&gt;은&lt;/p&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;777&quot; data-end=&quot;835&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-start=&quot;779&quot; data-end=&quot;835&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;&lt;b&gt;작업이 끝날 때까지 기다릴 것이냐, 말 것이냐&lt;/b&gt;&amp;rdquo;의 차이&lt;br /&gt;&amp;rarr; &quot;작업&lt;span&gt;&amp;nbsp;&lt;/span&gt;진입&lt;span&gt;&amp;nbsp;&lt;/span&gt;시점의 차이&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;837&quot; data-end=&quot;871&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Synchronous vs Asynchronous&lt;/b&gt;는&lt;/p&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;872&quot; data-end=&quot;927&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-start=&quot;874&quot; data-end=&quot;927&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;&lt;b&gt;결과를 직접 받느냐, 나중에 받느냐&lt;/b&gt;&amp;rdquo;의 차이&lt;br /&gt;&amp;rarr; &quot;작업&lt;span&gt;&amp;nbsp;&lt;/span&gt;종료&lt;span&gt;&amp;nbsp;&lt;/span&gt;시점의 처리 방식&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이렇게 봐도 아직도 헷갈릴 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blocking은 작업이 끝날 때 까지 기다리는데 Synchronous도 결과를 직접 받으려면 끝날 때 까지 기다려야 하는거 아니야?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 가질 수 있는 의문이기에 실제로 조합을 해서 비교해보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Blocking + Synchronous&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1745237858655&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void approvePayment(PaymentRequest request) {
    // 외부 PG사 API 호출 - 결과가 올 때까지 블로킹
    PaymentResult result = paymentGatewayClient.send(request);

    if (!result.isSuccess()) {
        throw new PaymentFailedException(&quot;결제 실패&quot;);
    }

    // 결제 승인 후 주문 상태 업데이트 (동기 처리)
    orderService.updateStatus(request.getOrderId(), &quot;PAID&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Non-Blocking + Synchronous&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1745237936127&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void useCoupon(String couponId, String userId) {
    // 락 시도 - 실패하면 바로 false 리턴 (Non-blocking)
    boolean lockAcquired = redisLock.tryLock(&quot;coupon:&quot; + couponId, 5);

    if (!lockAcquired) {
        throw new CouponAlreadyUsedException();
    }

    try {
        // 락 획득 후 쿠폰 사용 처리
        couponService.markAsUsed(couponId, userId);
    } finally {
        redisLock.release(&quot;coupon:&quot; + couponId);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Blocking + Asynchronous&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1745238055659&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void sendEmailAndWait(String email, String message) {
    Future&amp;lt;Result&amp;gt; result = emailSend(email, message);

    try {
        Result emailResult = result.get(10, TimeUnit.SECONDS); // 결과 받을 때까지 블로킹
        if (emailResult.isSuccess()) {
            throw new EmailSendException();
        }
    } catch (Exception e) {
        throw new EmailSendException(&quot;이메일 발송 실패&quot;, e);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Non-Blocking + Asynchronous&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1745238360909&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void sendOrderNotification(User user, Order order) {
    // Kafka Producer를 통해 논블로킹으로 이벤트 전송
    NotificationEvent event = new NotificationEvent(user.getId(), order.getId(), &quot;주문 완료&quot;);
    
    kafkaTemplate.send(&quot;notification-topic&quot;, event) // 즉시 반환됨
        .addCallback(
            success -&amp;gt; log.info(&quot;알림 이벤트 전송 성공&quot;),
            failure -&amp;gt; log.error(&quot;알림 이벤트 전송 실패&quot;, failure)
        );

    // 응답 확인 없이 다음 로직 바로 진행 (비동기 + 논블로킹)
    log.debug(&quot;알림 전송 요청 완료&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;올바른 예제 소스코드를 만든건지 나도 헷갈린다.&lt;/s&gt; 가장 중요한건 시점이라는걸 참고해서 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;blocking vs non-blocking은 결과가 나올 때 까지 기다리느냐?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;synchronous vs asynchronous는 제어 흐름의 주체가 누구한테 있느냐?(이 말이 어렵다면 단순하게 결과물을 직접 받아서 쓰느냐? 정도로 받아들여보자)&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>Asynchronous</category>
      <category>blocking</category>
      <category>Non-Blocking</category>
      <category>Synchronous</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/10</guid>
      <comments>https://icedstone.tistory.com/10#entry10comment</comments>
      <pubDate>Mon, 21 Apr 2025 21:36:36 +0900</pubDate>
    </item>
    <item>
      <title>JVM 메모리 구조</title>
      <link>https://icedstone.tistory.com/9</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ChatGPT Image 2025년 4월 19일 오후 06_21_19.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cs3uFB/btsNsoS4S82/qjHtCKl1tyamPy22zFFHLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cs3uFB/btsNsoS4S82/qjHtCKl1tyamPy22zFFHLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cs3uFB/btsNsoS4S82/qjHtCKl1tyamPy22zFFHLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcs3uFB%2FbtsNsoS4S82%2FqjHtCKl1tyamPy22zFFHLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;538&quot; height=&quot;538&quot; data-filename=&quot;ChatGPT Image 2025년 4월 19일 오후 06_21_19.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Method Area&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 정보(메서드, 필드, static 변수 등)를 저장&lt;/li&gt;
&lt;li&gt;ClassLoader에 의해 로딩된 클래스들의 메타데이터가 올라간다.&lt;/li&gt;
&lt;li&gt;Java 8 이전에는 PermGen, 이후에는 Metaspace로 대체됨&lt;/li&gt;
&lt;li&gt;모든 thread가 함께 사용&lt;/li&gt;
&lt;li&gt;해당 영역 안에 Runtime Constant Pool이 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Heap Area
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 객체 인스턴스(&lt;b&gt;&lt;i&gt;new&lt;/i&gt;&lt;/b&gt;)가 생성되는 영역&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1; text-align: left;&quot; href=&quot;https://icedstone.tistory.com/8&quot;&gt;GC의 주요 대상&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;모든 thread가 함께 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Stack Area
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드 호출 시 로컬 변수, 매개 변수, 리턴 주소 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PC register
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 실행 중인 JVM 명령의 주소를 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Native Method Stack
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JVM이 아닌 Native code(C, C++ 등)를 실행할 때 사용하는 Stack&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-8854862442299222&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745056100139&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Example {
	// Member Variable =&amp;gt; class 생성시 Heap Area에 저장
	String s1=  &quot;Hello&quot;;

	// Class Variable =&amp;gt; class 변수들은 classLoader에 의해 Class가 로드될 때 Method Area에 저장
	static String s2= &quot;World&quot;;

	// final로 선언하면 Class Variable은 상수로 치환되어 Method Area내부 Constant Pool
	static final String s3= &quot;JVM&quot;;

	public static void t1(int a) {// parameter Variable
	    // local Variable
		int b;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stack area - local Variable , Parameter Variable&lt;/li&gt;
&lt;li&gt;class(Methoed) area - Class Variable (static Variable)&lt;/li&gt;
&lt;li&gt;heap area -Member Variable(Instance Variable)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함께 알아두면 좋을 정보&lt;/p&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;initial heap size:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Larger of 1/64th of the machine's physical memory on the machine or some reasonable minimum. Before J2SE 5.0, the default initial heap size was a reasonable minimum, which varies by platform. You can override this default using the -Xms command-line option.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;maximum heap size:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Smaller of 1/4th of the physical memory or 1GB. Before J2SE 5.0, the default maximum heap size was 64MB. You can override this default using the -Xmx command-line option.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gc-ergonomics.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;오라클 문서&lt;/a&gt;에 따르면 heap memory의 default 값에 대해서 다음과 같이 설명하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 메모리 공간은&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실제 장착된 메모리 크기의 1/64 or 64MB 중 큰 값&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;최대 메모리 공간은&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실제 장착된 메모리 크기의 1/4 or 1GB 중 작은 값(J2SE 5.0 이전버전에서는 64MB)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;-- 위 설명을 보면 J2SE 5.0 버전 기준으로 되어있는데 최신 버전(오라클 기준)에서도 특별한 변경사항은 없는 것으로 보여집니다.(&lt;a href=&quot;https://docs.oracle.com/en/java/javase/24/gctuning/ergonomics.html#GUID-DB4CAE94-2041-4A16-90EC-6AE3D91EC1F1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JVM 24 기준&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>heap area</category>
      <category>Java</category>
      <category>jvm</category>
      <category>Memory</category>
      <category>method area</category>
      <category>Native Method stack</category>
      <category>pc register</category>
      <category>stack area</category>
      <category>메모리</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/9</guid>
      <comments>https://icedstone.tistory.com/9#entry9comment</comments>
      <pubDate>Sat, 19 Apr 2025 19:14:14 +0900</pubDate>
    </item>
    <item>
      <title>JVM GC(Garbage Collection)</title>
      <link>https://icedstone.tistory.com/8</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;C언어의 경우 malloc/free 를 통해서 프로그래머가 직접 메모리를 할당하고 해제해주지만 JVM의 경우에는 메모리를 알아서 관리해주고 있기 때문에 개발자가 직접 관리할 필요가 없어진다.&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;JVM에 다양한 메모리 영역이 존재하는데 그 중에서도 Heap영역에서 다음과 같이 GC가 동작한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Capture-2025-04-19-154145.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6cERT/btsNr99R403/ldzc5fesjjK3aEw67aPA3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6cERT/btsNr99R403/ldzc5fesjjK3aEw67aPA3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6cERT/btsNr99R403/ldzc5fesjjK3aEw67aPA3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6cERT%2FbtsNr99R403%2Fldzc5fesjjK3aEw67aPA3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;326&quot; height=&quot;489&quot; data-filename=&quot;Capture-2025-04-19-154145.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Eden, Survivor, Old 영역들이 존재하는데 간단하게 객체가 생성(&lt;i&gt;new Object()&lt;/i&gt;) 되면 Eden Space에 생겨난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고 나서 아직 참조가 되고있는 객체 더이상 참조 되지 않는 객체를 분류한다. 위의 그림에서 Object2가 Mark되어지고 MinorGC에 의해서 메모리 할당이 해제된것으로 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 생존한 객체들이 존재하는 Survivor영역을 왔다갔다 하면서 오래 살아남은 객체는 Old Generation으로 넘어가게 되고 추후 MajorGC가 동작할 때 확인하는 대상이 된다.&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;GC가 동작할 경우 STW(Stop The World)가 발생하게 되는데 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;b&gt;GC를 제외한 모든 쓰레드가 동작을 멈추기 때문에 GC가 벌어지는 동안 그 어떤 동작도 불가능하다.&lt;/b&gt;&lt;/u&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(GC의 진화과정을 보면은 이 STW시간을 최소화하려는 노력을 엿볼 수 있다. 운영상 튜닝 과정도 마찬가지로 이 시간을 최소화하기위한 설정이 많다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;같이 알아 두면 좋을 만한 내용&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Weak Generational hypothesis (David Ungar)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;'대부분의 객체는 금방 죽는다.' 그래서 Young Generation에서 빠르게 Minor GC가 발생하고 그래도 메모리 영역이 부족하면 Old Generation에서 Major GC가 발생하게 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- Mark And Sweep Algorithm&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;GC가 사용하는 가장 기본 적인 알고리즘이다. 영역을 Mark하고 삭제하게 되는데 메모리가 파편화되는 문제가 있어서 해결책으로 나온게 Mark And Compact Algorithm이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-8854862442299222&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;G1GC&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The first focus of G1 is to provide a solution for users running applications that require large heaps with limited GC latency. This means heap sizes of around 6 GB or larger, and a stable and predictable pause time below 0.5 seconds.&lt;br /&gt;- 오라클 공식 문서&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서 내용을 보면 대용량 heap size에서 0.5초 이내로 STW가 발생하는걸 목표로 하고있다. heap이 작은 application에서는 G1GC 사용을 권장하지 않으니 참고해두면 실무에서 적용하기 좋을 것이라 생각된다.&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;그러면 어떻게 STW 시간을 최소화 하고 있는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 세대의 GC에서는 메모리를 모두 훑어서 garbage를 정리하는 방식이다. G1은 메모리를 여러개의 작은 region으로 나누고 각 영역별로 효율적으로 수집할 곳을 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;garbage가 많은 영역을 미리 알고, 정리를 하기 때문에 STW를 짧게 가져갈 수 있게 된다. (그렇기에 G1 - Garbage First 라고 명칭한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* jdk7부터 사용 가능하며 jdk9부터는 default GC이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ZGC&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목표: 기존 GC의 경우 수십~수백 ms의 STW 조차도 대규모 실시간 서비스에는 치명적이기 때문에 시간을 극도록 줄이기 위하여 설계됨&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;기본적으로 기존 GC의 경우, 객체가 참조가 수정되면서 GC 중단이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에는 48비트 공간만을 활용해왔으나 64비트의 머신에서는 사용하지 않는 메모리 공간이 발생하였고, ZGC에서는 이 공간을 적극 활용하여 객체가 이동되는 순간에도 STW되지 않고 사용할 수 있도록 설계되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 일부 서버의 경우에는 ZGC사용이 불가능하다.&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>garbage collection</category>
      <category>GC</category>
      <category>heap</category>
      <category>Java</category>
      <category>jvm</category>
      <category>stw</category>
      <category>메모리</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/8</guid>
      <comments>https://icedstone.tistory.com/8#entry8comment</comments>
      <pubDate>Sat, 19 Apr 2025 16:26:51 +0900</pubDate>
    </item>
    <item>
      <title>JVM(Java Virtual Machine: 자바 가상 머신)</title>
      <link>https://icedstone.tistory.com/6</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;JVM은 하드웨어 및 운영 체제에 독립적인 실행 환경을 제공하며, 컴파일된 코드의 크기를 줄이고, 악성 프로그램으로부터 사용자를 보호하는 역할을 한다. - Oracle Javadoc&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM이 어떻게 저런걸 가능하게 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C언어의 경우에는 윈도우용 컴파일러, 리눅스용 컴파일러가 각자 컴파일을 진행하여 실행파일을 만들지만 Java의 경우에는 &lt;b&gt;각 환경에 맞는 JVM이 따로 존재&lt;/b&gt;하기 때문에 자바 컴파일러(javac)가 번역한 class file을 어느환경에서나 실행이 가능해진다.&lt;/p&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-origin-width=&quot;696&quot; data-origin-height=&quot;593&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o56nY/btsMJMfwJCE/0LCBjM0uf6vZgej1OzqPU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o56nY/btsMJMfwJCE/0LCBjM0uf6vZgej1OzqPU1/img.png&quot; data-alt=&quot;출처: https://steady-snail.tistory.com/67&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o56nY/btsMJMfwJCE/0LCBjM0uf6vZgej1OzqPU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo56nY%2FbtsMJMfwJCE%2F0LCBjM0uf6vZgej1OzqPU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;429&quot; height=&quot;366&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;593&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://steady-snail.tistory.com/67&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 만들어진 byte code는 JVM이 실행할 수 있는 &lt;b&gt;추상적인 명령어 집합&lt;/b&gt;이므로 기계어보다 간결하다. CPU 명령어, 레지스터 정보 등 다양한 정보를 포함해야하는 기계어보다 컴파일된 코드의 사이즈는 작아진다.&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;이 때, class를 읽어올 때 &lt;b&gt;byte code를 검증&lt;/b&gt;하고 메모리관리를 JVM이 직접하기 때문에 사용자가 메모리를 해제하는 과정에서 발생할 수 있는 보안문제를 막을 수 있다. 그 외에도 JVM내 보안 관리자(&lt;b&gt;Java Security Manager&lt;/b&gt;)가 있어서 내부적으로 작업을 제한하는게 가능하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같이 공부하면 좋은 내용 (관련 내용 작성 예정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://icedstone.tistory.com/8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JVM GC&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://icedstone.tistory.com/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JVM 메모리 구조&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;a href=&quot;https://icedstone.tistory.com/7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; JVM 초기화 과정(Loading, Linking, Initialization)&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/javase/specs/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #777777; text-align: center;&quot;&gt;&lt;a href=&quot;https://steady-snail.tistory.com/67&quot;&gt;https://steady-snail.tistory.com/67&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/1230&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://d2.naver.com/helloworld/1230&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://style-tech.tistory.com/22&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://style-tech.tistory.com/22&lt;/a&gt;&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>Java</category>
      <category>jvm</category>
      <category>자바</category>
      <category>자바가상머신</category>
      <author>icedstone</author>
      <guid isPermaLink="true">https://icedstone.tistory.com/6</guid>
      <comments>https://icedstone.tistory.com/6#entry6comment</comments>
      <pubDate>Thu, 13 Mar 2025 18:57:05 +0900</pubDate>
    </item>
  </channel>
</rss>