본문 바로가기

전체 글53

[ Java ] 600KB 배열인데, G1 GC에서는 왜 1MB짜리 공간을 차지할까? 자바에서 다음 배열을 만들었다고 생각해보자.byte[] data = new byte[600 * 1024];데이터가 약 600KB니까 객체 헤더 정도만 더하면 되겠지?객체 자체의 크기를 생각하면 맞는 방향이다.그런데 GC가 이 객체를 배치하기 위해 확보하는 공간까지 생각하면 이야기가 달라질 수 있다.G1에서는 이 배열 하나가 1MB짜리 리전 하나를 차지할 수 있다.그리고 남은 공간에는 다른 객체를 넣지 못한다.(분명히 비어 있는데 사용은 못 한다고?)이번에는 G1 GC의 Humongous 객체를 실제 로그로 확인해보자.본문에서는 단위를 정확히 구분하기 위해 KiB와 MiB를 사용한다. 1KiB는 1,024바이트, 1MiB는 1,024KiB다.1. G1은 힙을 리전으로 나눈다G1은 힙을 동일한 크기의 리전(.. 2026. 10. 12.
[ Spring Boot ] 주문은 저장됐는데 이벤트는 사라졌다? 트랜잭셔널 아웃박스 패턴 주문을 저장하고, 다른 서비스에 주문이 생성되었다고 알려준다고 가정해보겠습니다. ( 갑작스러운 공격!!! )@Transactionalpublic void createOrder(CreateOrderRequest request) { Order order = orderRepository.save(request.toEntity()); eventPublisher.publish(new OrderCreated(order.getId()));}DB에도 저장하고 이벤트도 발행했습니다.그런데 여기서 조금 불안한 부분이 있습니다.“이벤트 발행은 성공했는데, DB 커밋이 실패하면?”“DB부터 커밋하고 보내면 안전한가?”흠.. 순서를 바꾸는 것만으로는 해결되지 않습니다.이번에는 DB 변경과 이벤트 발행 사이에서 생기는.. 2026. 10. 4.
[ 네트워크 ] TCP로 두 번 보냈는데, 왜 한 번에 읽힐까? 오늘은 미루고 미루던 네트워크입니다.. ㅠㅠ 우선 소켓 통신을 만든다고 가정해보겠습니다.보내는 쪽에서 HELLO와 WORLD를 따로 전송했습니다.out.write("HELLO".getBytes(StandardCharsets.UTF_8));out.write("WORLD".getBytes(StandardCharsets.UTF_8));out.flush();받는 쪽에서도 두 번 읽으면 하나씩 나오겠죠?흠.. TCP에서는 그렇게 약속하지 않습니다.한 번에 HELLOWORLD가 읽힐 수도 있고, HEL, LOWO, RLD처럼 나뉘어 읽힐 수도 있습니다.“TCP는 순서를 보장한다면서 왜 섞여서 오는 거지?”이번에는 바이트의 순서와 메시지의 경계를 구분해보겠습니다!TCP가 전달하는 것은 바이트 스트림이다위에서 가능한 .. 2026. 9. 30.
[ Java / Spring Boot ] @Bean 메서드를 직접 호출했는데, 왜 같은 객체가 나올까? 오늘의 타겟은 Spring입니다. Spring Boot에서 설정 클래스를 작성하다 보면 이런 코드를 만나게 됩니다.@Configurationpublic class AppConfig { @Bean public Repository repository() { return new Repository(); } @Bean public OrderService orderService() { return new OrderService(repository()); }}repository() 안에는 분명 new가 있습니다.그런데 orderService()에서 이 메서드를 직접 호출해도, 컨테이너에서 조회한 Repository와 같은 객체가 들어갑니다.“자바 메서드를 .. 2026. 9. 29.
[ Java ] PriorityQueue에 하나씩 넣으면 O(n log n)인데, 한 번에 만들면 O(n)이라고? 지난 글에 이어서 PQ를 또 후두리찹찹 해보도록 하겠습니다. 우선순위 큐를 처음 채울 때 보통 이렇게 작성합니다.PriorityQueue pq = new PriorityQueue();for (int value : values) { pq.offer(value);}원소 하나를 넣을 때 힙을 조정하는 비용이 O(log n)이니까, n개를 넣으면 최악 O(n log n)입니다.그런데 이미 리스트에 값이 모여 있다면 이렇게도 만들 수 있습니다.List values = Arrays.asList(7, 6, 5, 4, 3, 2, 1);PriorityQueue pq = new PriorityQueue(values);이 경로의 힙 구성은 O(n)입니다.“같은 값을 넣는데, 생성자로 넘기면 더 싸다고?”(생성자가 반복.. 2026. 9. 28.
[ Java ] PriorityQueue에 넣은 값을 바꿨는데, 왜 꺼내는 순서는 그대로일까? 코테를 풀다 보면 우선순위 큐를 자주 사용하게 됩니다. 작은 값부터 꺼내고 싶으면 PriorityQueue에 넣고, poll()로 하나씩 꺼내면 되죠. 그런데 객체를 넣었다면? 그리고 큐에 넣은 뒤에 그 객체의 우선순위를 바꿨다면? “값이 작아졌으니까 알아서 먼저 나오겠지?” ( 4개월 전 작성자의 크나큰 실수.. ) 흠..? 정말 그렇게 동작하는지 살펴보겠습니다!분명 1로 바꿨는데, 10이 먼저 나온다숫자가 작을수록 먼저 처리하는 작업 큐를 만들어보겠습니다.import java.util.Comparator;import java.util.PriorityQueue;public class PriorityQueueMutationDemo { static class Task { final Str.. 2026. 9. 27.