프로그래밍 기초
- 값 호출 (Call by Value)와 참조 호출 (Call by Reference)의 차이는 무엇인가요?
- Call by Value:
- 호출 시 인자에 값을 복사해 넘기는 것
- 메서드 내에서 값을 변경해도 본래 변수는 영향 받지 않음.
- Call by Reference:
- 호출 시 인자에 참조자를 넘기는 것
- 메서드 내에서 오브젝트를 변경하면 본래 오브젝트도 변경됨.
- Call by Value:
- 얕은 복사 (Shallow Copy)와 깊은 복사 (Deep Copy)는 어떻게 다른가요?
- Shallow Copy: 오브젝트 참조자를 복사. 따라서 같은 오브젝트를 포인터가 가리키고 있음.
- Deep Copy: 메모리에 오브젝트를 따로 복사. 따라서 2개의 오브젝트가 생성.
- Stack overflow 에러를 만나본적이 있나요? 있다면 어떤 경우에 발생했었나요?
- 컴퓨터 프로그램이 Stack에서 할당량을 넘기는 메모리를 사용했을 때 발생하게 됩니다.
- 재귀 함수에서 많이 발생되는 에러.
- 디버거를 사용해보셨나요? 브레이크 포인트란 무엇인가요?
- Debugger: 오류를 찾기 위해 Debugging을 도와주는 도구. 코드 각 줄 혹은 메소드 단위로 진행시켜 결과값을 보여주는 도구.
- Break Point: Debugger로 Debugging을 할때 코드에 Break Point를 설정하면 해당 줄 이전까지만 코드를 진행.
인코딩
- UTF-8 / UTF-16의 차이점은 무엇인가요?
- UTF = Unicode Transformation Format - N-bit
- UTF-8:
- 기본 1 byte (1, 2, 3, 4). 단위 8 bit
- 장점 - 하위 호환성 보장, 간단한 인코딩 변환, 바이트 검색 알고리즘 사용, 쉬운 바이트 경계 파악, 문자 표현 독립성, 빠른 인코딩.
- 단점 - 문자열 표현 용량이 큼.
- UTF-16:
- 기본 2 byte (2, 4). 단위 16 bit
Java
- 자바의 static 변수는 무엇인가요? 아는대로 설명해주세요 (특징, 사용법, 주의사항 등)
- static 변수는 new 키워드를 통해서 Heap Memory 공간에 인스턴스 생성되는 것이 아니라 프로세스가 메모리에 로드 될 때 Data Memory 영역에 같이 변수로 생성됩니다. 따라서 프로세스가 끝나기 전까지 메모리에 로드 되어 있는 변수입니다.
- 사용방법은 변수 타입명 뒤에 static 키워드를 기입하여 사용합니다.
- 해당 변수는 프로세스가 종료되기 전까지 메모리에 로드 되어 있기 때문에 과부화나 불필요하게 메모리 공간을 차지하는 것에 주의해야합니다.
- 프로세스와 스레드의 차이점은 무엇인가요?
- 프로세스 Process:
- 실행 중인 프로그램 = 디스크에 있는 프로그램이 메모리에 적재된 상태, 운영체제의 제어를 받는 상태
- 프로세스는 자신만의 자원을 가진다.
- 프로세스끼리는 서로 독립적이다.
- 스레드 Thread:
- 하나의 프로그램 실행 흐름 = 프로세스 내부에 존재, 프로세스는 적어도 하나의 스레드를 가진다.
- 프로세스에 비해 필요 자원이 적다.
- 경량 프로세스라고도 한다.
- 스레드 간 자원을 공유한다.
- 프로세스 Process:
- 스레드 세이프 (thread safe)는 무엇인가요?
- 멀티 스레드 프로그램에서 여러 스레드가 공유 자원에 접근하여도 프로그램 실행에 있어 문제가 없는 상태를 뜻합니다.
- 공유 자원을 동시에 접근하게 되면 실행 순서에 따라 결과값이 달라져 데이터 불일치가 일어날 수 있습니다.
- 스레드 세이프를 지키는 4가지 방법
- Mutual Exclusion 상호 배제
- 하나의 스레드만 공유자원에 접근할 수 있도록 Mutex와 Semaphore로 Lock을 통제해주는 방법입니다.
- Atomic Operation 원자 연산
- 공유 자원에 접근할 때 원자 연산을 이용하거나 '원자적'으로 정의된 접근 방법을 사용함으로써 상호 배제하는 방법이다.
- Atomic - 공유 자원 변경에 필요한 연산을 원자적으로 분리한 뒤, 실제로 데이터의 변경이 이루어지는 시점에 Lock 을 걸고, 데이터를 변경하는 시간 동안, 다른 쓰레드의 접근이 불가능하도록 하는 방법입니다.
- Thread-Local Storage 쓰레드 지역 저장소
- 공유 자원의 사용을 최대한 줄이고, 각각의 쓰레드에서만 접근 가능한 저장소들을 사용함으로써 동시 접근을 막는 방법입니다.
- 일반적으로 공유상태를 피할 수 없을 때 사용하는 방식입니다.
- Re-Entrancy 재진입성
- 쓰레드 호출과 상관 없이 프로그램에 문제가 없도록 작성하는 방법입니다.
- Mutual Exclusion 상호 배제
- 스레드 세이프를 지키는 4가지 방법
- 경량 스레드 (virtual thread)란 무엇인가요? -- (마지막 참고자료 인용)
- 경량 스레드는 가상 스레드라고 불리기도 하며 영문으로 light-weight thread라고도 불립니다.
- OS 스레드를 그대로 사용하지 않고 JVM 자체적으로 내부 스케줄링을 통해서 사용할 수 있는 경량의 스레드를 제공합니다. 하나의 Java 프로세스가 수십만~ 수백만개의 스레드를 동시에 실행할 수 있게끔 설계되었습니다.
- 개발 배경
- 자바의 스레드는 OS의 스레드를 기반으로 한다.
- 자바의 전통적인 스레드는 OS 스레드를 랩핑(wrapping)한 것으로 이를 플랫폼 스레드 라고 정의한다. (자바의 전통적인 스레드=플랫폼 스레드)
- 따라서 Java 애플리케이션에서 스레드를 사용하는 코드는 실제적으로는 OS 스레드를 이용하는 방식으로 동작했다.
- OS 커널에서 사용할 수 있는 스레드는 갯수가 제한적이고 생성과 유지 비용이 비싸다.
- 이 때문에 기존에 애플리케이션들은 비싼 자원인 플랫폼 스레드를 효율적으로 사용하기 위해서 스레드 풀(Thread Pool) 만들어서 사용해왔다.
- 처리량(throughput)의 한계
- Spring Boot와 같은 애플리케이션의 기본적인 사용자 요청 처리 방식은 Thread Per Request 이다. 이는 하나의 request(요청)을 처리하기 위해서 하나의 스레드를 사용한다.
- 애플리케이션에서 처리량을 늘리려면 스레드를 늘려야 하지만 스레드를 무한정 늘릴 수 없다. (OS 스레드를 무한정 늘릴 수 없기 때문)
- 따라서 애플리케이션의 처리량(throughput)은 스레드 풀에서 감당할 수 있는 범위를 넘어서 늘어날 수 없다.
- Blocking으로 인한 리소스 낭비
- Thread per Request 모델에서는 요청을 처리하는 스레드에서 IO 작업 처리할 때 Blocking 이 일어난다.
- 이 때문에 스레드는 IO 작업이 마칠 때까지 다른 요청을 처리하지 못하고 기다려야 한다.(Blocking 동안 대기)
- 애플리케이션에 유입되는 요청이 많지 않거나 또는 스케일 아웃으로 충분히 커버할 수 있는 정도라면 문제가 없지만,
- 아주 많은 요청을 처리해야하는 상황이라면 Blocking 방식으로 인해 발생하는 낭비를 줄여야 할 필요가 있다.
- 이 때문에 Blocking 이 아니라 Non-blocknig 방식의 Reactive Programming이 발전하였다.
- Reactive Programming의 단점
- 처리량을 높이기 위한 방법으로 비동기 방식의 Reactive 프로그래밍이 발전해왔다.
- 한정된 자원인 플랫폼 스레드가 Blocking 되면서 대기하는 데 소요된 스레드 자원을 Non-blocking 방식으로 변경하면서 다른 요청을 처리하는데 사용할 수 있게 되었다.
- 대표적으로 Webflux 가 이렇게 Non-blocking으로 동작한다.
- 다만 이런 Reactive 코드는 작성하고 이해하는 비용을 높게 만들었다. (Mono, Flux)
- 또한 기존의 자바 프로그래밍의 패러다임은 스레드를 기반으로 하기 때문에 라이브러리들 모두 Reactive 방식에 맞게 새롭게 작성되어야 하는 문제가 있다.
- 자바 플랫폼의 디자인
- 자바 플랫폼은 전통적으로 스레드를 중심으로 구성되어 있었다.
- 스레드 호출 스택은 thread local을 사용하여 데이터와 컨텍스트를 연결하도록 설계되어 있다.
- 이 외에도 Exception, Debugger, Profile(JFR)이 모두 스레드를 기반으로 하고 있다.
- Reactive 스타일로 코드를 작성하면 사용자의 요청이 스레드를 넘나들면서 처리되는데, 이 때문에 컨텍스트 확인이 어려워져 결국 디버깅이 힘들어졌다.
- 자바의 스레드는 OS의 스레드를 기반으로 한다.
- 해결하고자 하는 문제
- Java 개발자가 하드웨어의 성능을 잘 활용하는 높은 처리량(쓰루풋)의 서버를 작성하는 것
- 가상 스레드는 Blocking 이 발생하면 내부적으로 스케줄링을 활용하여 플랫폼 스레드가 그냥 대기하게 두지 않고 다른 가상 스레드가 작업할 수 있도록 한다.
- 따라서 Reactive programming 의 Non-blcking 과 동일하게 플랫폼 스레드의 리소스를 낭비하지 않는다.
- 동시에 자바 플랫폼의 디자인과 조화를 이루는 코드를 생성할 수 있도록 하는 것
- 기존 Reactive programming 의 장점에도 불구하고 전통적인 자바 언어의 구조는 스레드를 기반으로 하였기 때문에 Webflux등을 사용할 때 디버깅, 성능테스트가 어려웠다.
- 하지만 가상 스레드는 기존 스레드 구조를 그대로 사용하기 때문에 디버깅, 프로파일링등 기존의 도구도 그대로 사용할 수 있다.
- Java 개발자가 하드웨어의 성능을 잘 활용하는 높은 처리량(쓰루풋)의 서버를 작성하는 것
- Reactive Programming 과의 비교
- Reactive programming 이 달성하고자 하는, 리소스를 효율적으로 사용하여 높은 처리량(throughput)을 감당하려는 목적은 동일하다.
- 가상 스레드를 사용하면 Non-blocking 에 대한 처리를 JVM 레벨에서 담당해준다.
- 따라서 Spring Web MVC 스타일로 코드를 작성하더라도 내부에서 가상 스레드가 기존의 플랫폼 스레드를 직접 사용하는 방식보다 효율적으로 스케줄링하여 처리량을 높일 수 있다.
- 결론적으로 가상 스레드 는 기존 스레드 방식의 이점을 누리면서도 Reactive programming의 장점을 취할 수 있다.
참고자료
[OS] 쓰레드 세이프(Tread Safe)란?
쓰레드 세이프(Thread Safe)란? 멀티 쓰레드 프로그래밍에서, 어떤 공유 자원에 여러 쓰레드가 동시에 접근해도, 프로그램 실행에 문제가 없는 상태를 의미합니다. Thread Safe 를 지키기 위한 방법은
wooono.tistory.com
자바에서 static 변수, 메서드 (클래스 변수, 메서드)
(** 자바를 기반으로 설명하지만 C++도 크게 다르지 않습니다. 다만, C++은 전역변수를 사용할 수 있기 때문에 static 변수외에도 다른 방법으로 값을 공유 할 수 있습니다 **) 자바는 class를 만들고 cl
42place.innovationacademy.kr
Virtual Thread란 무엇일까? (1)
Software Developer, I love code.
findstar.pe.kr
반응형
'컴퓨터과학 > 기본 프로그래밍 지식' 카테고리의 다른 글
노드(Node)란? (0) | 2025.01.08 |
---|---|
[기본 지식] 의존성 주입(DI, Dependency Injection) (0) | 2023.09.22 |
[기본 지식] 디자인 패턴 - 싱글톤 패턴(Singleton Pattern) (0) | 2023.09.21 |
[기본 지식] HTTP 이해 (0) | 2023.08.02 |
[기본 지식] 프로토콜 Protocol (0) | 2023.08.02 |