유한 오토마타는 신이야
우리는 상태머신을 왜 사용해야하는가

Search for a command to run...
우리는 상태머신을 왜 사용해야하는가

8코어 노드에 컨테이너를 띄웠는데 ForkJoinPool이 스레드를 한두 개만 만들어요. 메모리는 넉넉히 줬는데 컨테이너가 자꾸 OOMKilled로 죽고요. 분명히 같은 JAR인데 로컬에서는 멀쩡하다가 쿠버네티스에만 올리면 이상해져요. 이 글은 "왜 컨테이너 속 JVM은 다르게 행동하는가"를 cgroup이라는 진짜 경계선과, JVM이 그 경계를 읽어내는 내
Executors.newFixedThreadPool(10) 한 줄을 쓰면서도, 11번째 작업이 오면 스레드가 11개로 늘어날 거라고 막연히 기대해 본 적 없으신가요. 실제로는 큐가 먼저 무한히 쌓이고 스레드는 영원히 10개에 머물러요. 이 글은 ThreadPoolExecutor가 작업을 받았을 때 "스레드를 새로 만들지, 큐에 넣을지, 거부할지"를 결정하는
synchronized 키워드 하나로 스레드 안전을 얻는 동안, JVM 안에서는 객체 헤더의 비트를 뒤집고, 스택에 락 레코드를 쌓고, 경합이 생기면 네이티브 모니터로 승격하는 일이 벌어져요. 이 글은 그 한 번의 잠금이 객체 헤더부터 ObjectMonitor까지 어떤 경로를 거치는지, 그리고 한때 있었다가 JDK 18에서 사라진 biased locking
Java에서 new를 호출하면 무슨 일이 벌어질까요? "힙에 메모리를 잡는다"는 한 문장 뒤에는 스레드마다 자기만의 분양 구역을 나눠 갖는 정교한 설계가 숨어 있어요. 이 글은 HotSpot JVM이 객체 할당을 어떻게 "거의 공짜"로 만드는지 그 내부를 따라가 보려는 글이에요. JVM 메모리 동작 원리에 관심 있는 분께 권해요. 자바를 쓰다 보면 객체를
"파일을 읽어서 소켓으로 보낸다." 한 줄짜리 요구사항이에요. 그런데 이 한 줄 뒤에서 데이터는 메모리를 네 번이나 복사하고, CPU는 커널과 유저 공간을 네 번이나 들락거려요. Kafka처럼 초당 수십만 건을 흘려보내야 하는 시스템에서 이 비용은 그냥 넘길 수가 없어요. 이 글은 그 복사를 한 겹씩 벗겨내는 zero-copy의 동작 원리를 따라가요. 전통
git merge를 매일 쓰지만, 그 한 줄이 안에서 무슨 일을 하는지 들여다본 적은 드물어요. 이 글은 merge가 두 갈래의 변경을 어떻게 합치는지, merge base가 왜 필요한지, 그리고 Git이 기본 전략을 recursive에서 ort로 갈아치운 이유를 따라가요. Git을 쓰는 백엔드 개발자를 대상으로 해요. 브랜치 두 개를 합치는 일은 겉보기
Netty가 빠른 이유, Kafka 클라이언트가 직렬화에 신경 쓰는 이유, MappedByteBuffer로 수 GB짜리 파일을 다루는 이유. 그 한가운데에는 ByteBuffer가 있어요. 이번 글에서는 ByteBuffer의 두 얼굴 — heap과 direct — 가 어떻게 다른지, off-heap 메모리는 어떻게 잡고 어떻게 풀리는지, JVM과 운영체제 사
JFR을 켜면 1% 미만 오버헤드로 JVM 내부가 그대로 기록돼요. 어떻게 이렇게 가벼울 수 있는지, 그리고 그 데이터가 어떤 경로를 거쳐 디스크에 쌓이는지 한 번 따라가 봐요. 이 글은 JFR을 "그냥 잘 쓰는 도구"에서 "내부 동작을 아는 도구"로 끌어올리고 싶은 분을 위한 글이에요. 운영 중인 서버에서 갑자기 응답 시간이 튀어요. 메트릭 그래프는 분