JSCODE 제이온
@jayon0927
수강생
1,787
수강평
84
강의 평점
5.0
게시글
질문&답변
멀티스레드
안녕하세요, Cola님! 람다와 스트림이 멀티스레드 환경에 안전하다는 건 "순수 함수로 사용한다는 전제 아래" 안전하다는 의미예요.스트림 API는 각 연산이 stateless하고 부수효과를 일으키지 않는다는 것을 전제로 설계되어 있습니다. 이 전제만 지키면 parallelStream()으로 병렬 처리해도 race condition 없이 안전하게 동작합니다. Java 공식 문서에서도 스트림 연산은 stateless해야 한다고 명시되어 있고요. 말씀하신 대로 람다 내부에서 외부 변수를 수정하거나 공유 상태에 부수효과를 일으키면 당연히 안전하지 않습니다. 다만 이 경우는 스트림이 안전하지 않은 게 아니라, 함수형 프로그래밍의 설계 원칙을 사용자가 깬 것이라고 보시는 게 맞아요. 자료에서 "안전하다"고 한 건 의도된 사용 방식, 즉 순수 함수로 작성하는 경우를 전제한 표현입니다. 면접에서는 "스트림은 stateless한 순수 함수로 작성하는 것을 전제로 설계되어 있어서, 이 약속만 지키면 parallelStream()에서도 안전하게 동작합니다. 부수효과가 있는 람다를 쓰면 그건 함수형 원칙을 깬 것이지 스트림의 한계는 아닙니다" 정도로 답변하시면 됩니다.
- 좋아요수
- 1
- 댓글수
- 2
- 조회수
- 22
질문&답변
성능 오버헤드
안녕하세요, Cola님!사실 일반적인 시스템에서 instanceof로 인해 성능 상의 큰 문제가 되는 건 많지는 않습니다.정확히는 상속의 깊이가 깊어지고, 해당 상속으로 이어지는 클래스가 많을 경우 이들을 순회하면서 타입을 찾는데요! 이러한 수십 ~ 수백 개 이상의 클래스가 상속 구조로 연결된 형태가 많은 거대한 애플리케이션이라면 문제가 생길 여지가 있습니다. 물론 이보다는 다형성을 깨뜨리는 점이 더 메인 문제점이지만, 성능 오버헤드도 알아두면 좋겠어서 자료로 포함하게 되었습니다.
- 좋아요수
- 1
- 댓글수
- 2
- 조회수
- 28
질문&답변
volatile에 대해 질문 있습니다.
안녕하세요, Cola님!꽤 좋은 질문을 해주셨네요 ㅎㅎ 두 설명은 사실 모순되는 게 아니라 서로 다른 측면을 다루고 있습니다.우리 자료의 설명: 가시성 문제가 왜 발생하는지 => 코어별 캐시 구조가 근본 원인다른 자료의 설명: volatile이 어떻게 해결하는지 => happens-before와 메모리 배리어 우리 자료에서 설명하는 "코어별 캐시로 인한 가시성 문제"는 자바 메모리 모델 학습의 표준 출발점이고, 멀티 코어 환경에서 각 CPU 코어가 독립적인 캐시를 갖기 때문에 가시성 문제가 발생한다는 점은 정확한 설명입니다. Cola 님이 보신 다른 자료는 volatile이 이 문제를 어떻게 해결하느냐를 다루는 부분이에요. Java 5(JSR-133) 이후 volatile은 happens-before 관계 형성과 메모리 배리어 삽입으로 동작하며, 이 메모리 배리어가 실행될 때 결국 CPU 캐시 일관성을 강제 동기화하는 효과를 냅니다. 두 설명은 같은 현상의 원인과 해결 메커니즘을 각각 다루는 것이라, 충돌이 아닌 상호 보완 관계입니다.면접에서 만약 둘을 묶어서 답변하시고 싶다면, 아래 형태를 고려해보시면 됩니다! "멀티 코어 환경에서 각 코어가 독립적인 캐시를 갖기 때문에 가시성 문제가 발생합니다. volatile은 happens-before 관계와 메모리 배리어를 통해 이 캐시 간 동기화를 강제하여, 다른 스레드가 최신 값을 읽을 수 있게 보장합니다."
- 좋아요수
- 2
- 댓글수
- 2
- 조회수
- 37
질문&답변
GC 알고리즘
안녕하세요, Cola님!Mark and Sweep을 핵심 키워드로 가져가시는 건 충분히 괜찮습니다. Mark는 모든 GC 알고리즘의 공통 출발점이라, 어느 컬렉터를 쓰더라도 "GC Root에서 시작해 reachable 객체를 마킹한다"는 점은 동일하기 때문이에요. 다만 면접 답변을 더 풍성하게 가져가시려면, Mark and Sweep 외에 함께 알아두시면 좋은 알고리즘 두 가지가 있습니다.Mark and Compact: 마킹 후 살아남은 객체를 한쪽으로 모아 정리 → Mark and Sweep의 단편화 문제를 해결, Old Generation에서 사용Copying: 살아남은 객체를 다른 영역으로 복사 → Young Generation의 Eden ↔ Survivor 사이 이동에 사용 전체 구조로 정리하면 이렇습니다.[GC의 큰 틀] └ Mark and Sweep (마킹 → 정리) [영역별 정리 방식] ├ Young Generation : Copying └ Old Generation : Mark and Sweep / Mark and Compact 면접에서 "GC 동작 원리"가 메인 질문으로 나오면 Mark and Sweep을 출발점으로 답변하시고, 후속 질문이 들어올 때 위 두 알고리즘으로 확장하시면 됩니다!
- 좋아요수
- 1
- 댓글수
- 2
- 조회수
- 32
질문&답변
Mark and Sweep
안녕하세요, Cola님!자료의 "Mark and Sweep" 표현은 마킹을 통해 비활성 객체를 정리한다는 GC 동작의 큰 흐름을 통칭하는 의미로 사용한 것입니다. Mark는 모든 GC 알고리즘의 공통 1단계라, GC의 핵심 원리로 함께 언급되는 경우가 많습니다. 더 엄밀한 알고리즘 분류로는 영역별로 나뉩니다.Young Generation (Eden ↔ Survivor): Copying 방식 (말씀해 주신 내용)Old Generation: Mark and Sweep / Mark and Compact
- 좋아요수
- 1
- 댓글수
- 1
- 조회수
- 35
질문&답변
용어 질문
안녕하세요, Cola님!두 표현 모두 같은 개념을 가리키는 유효한 표현이고, 의미상 차이는 없습니다.Root Space: GC가 reachability 분석을 시작하는 출발점이 위치한 영역을 가리키는 표현GC Root / GC Roots: 같은 개념을 영문 표준 자료(Eclipse MAT, JVM 공식 문서, Baeldung 등)에서 자주 부르는 표현둘 다 스택의 로컬 변수, 정적 변수, JNI 참조, 활성 스레드처럼 "GC가 traverse를 시작하는 기점"을 의미하며, 어느 표현을 사용하셔도 무방합니다!
- 좋아요수
- 1
- 댓글수
- 1
- 조회수
- 25
질문&답변
호출횟수 질문입니다.
안녕하세요, Cola님! 자료의 2,000 / 15,000은 HotSpot JVM의 Tiered Compilation 기본값으로, -XX:Tier3CompileThreshold, -XX:Tier4CompileThreshold 옵션에 해당합니다. 이 값은 Tiered Compilation이 기본 활성화된 Java 8 이후 최신 OpenJDK HotSpot까지 동일하게 유지되고 있습니다. OpenJDK 소스 트리의 테스트 코드(CheckCompileThresholdScaling.java)에서도 같은 값으로 검증되고 있습니다. 그래서 OpenJDK HotSpot 기준으로는 버전 차이를 신경 쓰지 않으셔도 됩니다. 직접 확인하시려면 다음 명령어를 수행해 보시면 됩니다.java -XX:+PrintFlagsFinal -version | grep CompileThreshold 다른 JVM 벤더(OpenJ9, GraalVM 등)는 정책이 달라 수치가 다를 수 있지만, OpenJDK HotSpot 기준으로 약 2,000 / 약 15,000으로 외워두시면 충분합니다. 참고: https://devblogs.microsoft.com/java/how-tiered-compilation-works-in-openjdk/
- 좋아요수
- 1
- 댓글수
- 2
- 조회수
- 37
질문&답변
실행과정 질문입니다.
안녕하세요, Cola님! 좋은 질문이에요.말씀하신 대로 시간 순서로 보면 컴파일이 먼저 일어나는 게 맞습니다. .java가 .class로 변환되어 있어야 JVM이 그걸 로딩해서 실행할 수 있으니까요. IntelliJ에서 Run 버튼을 누르면 IDE가 빌드 단계에서 컴파일을 먼저 처리하고, 그 다음에 JVM이 뜨는 흐름입니다. 자료의 첫째~다섯째는 시간순을 엄격하게 따라가는 나열이라기보다는, Java 실행을 구성하는 단계들을 묶어 정리한 구조로 봐주시면 됩니다. 첫째의 "프로그램이 실행되면"은 JVM이 기동되는 시점을 가리키고, 둘째 컴파일 부분은 JVM이 로딩할 .class가 어떻게 준비되는지를 같이 짚어주는 흐름이라고 보시면 됩니다. 시간 순으로 정리하면 이렇습니다..java → .class 컴파일java 명령으로 JVM 시작, OS로부터 메모리 할당클래스 로더가 .class 로딩실행 엔진이 바이트코드 실행실행 중 GC가 메모리 관리 꼼꼼히 봐주셔서 감사합니다!! 😊
- 좋아요수
- 2
- 댓글수
- 1
- 조회수
- 37




