본문 바로가기

기본 프로그래밍 지식

[기본 지식] 퀴즈 1 - 프로그래밍 기초, 인코딩, Java

반응형

프로그래밍 기초

  1. 값 호출 (Call by Value)와 참조 호출 (Call by Reference)의 차이는 무엇인가요?
    • Call by Value:
      • 호출 시 인자에 값을 복사해 넘기는 것
      • 메서드 내에서 값을 변경해도 본래 변수는 영향 받지 않음.
    • Call by Reference:
      • 호출 시 인자에 참조자를 넘기는 것
      • 메서드 내에서 오브젝트를 변경하면 본래 오브젝트도 변경됨.
  2. 얕은 복사 (Shallow Copy)와 깊은 복사 (Deep Copy)는 어떻게 다른가요?
    • Shallow Copy: 오브젝트 참조자를 복사. 따라서 같은 오브젝트를 포인터가 가리키고 있음.
    • Deep Copy: 메모리에 오브젝트를 따로 복사. 따라서 2개의 오브젝트가 생성.
  3. Stack overflow 에러를 만나본적이 있나요? 있다면 어떤 경우에 발생했었나요?
    • 컴퓨터 프로그램이 Stack에서 할당량을 넘기는 메모리를 사용했을 때 발생하게 됩니다. 
    • 재귀 함수에서 많이 발생되는 에러.
  4. 디버거를 사용해보셨나요? 브레이크 포인트란 무엇인가요?
    • Debugger: 오류를 찾기 위해 Debugging을 도와주는 도구. 코드 각 줄 혹은 메소드 단위로 진행시켜 결과값을 보여주는 도구.
    • Break Point: Debugger로 Debugging을 할때 코드에 Break Point를 설정하면 해당 줄 이전까지만 코드를 진행.

인코딩

  1. 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

  1. 자바의 static 변수는 무엇인가요? 아는대로 설명해주세요 (특징, 사용법, 주의사항 등)
    • static 변수는 new 키워드를 통해서 Heap Memory 공간에 인스턴스 생성되는 것이 아니라 프로세스가 메모리에 로드 될 때 Data Memory 영역에 같이 변수로 생성됩니다. 따라서 프로세스가 끝나기 전까지 메모리에 로드 되어 있는 변수입니다. 
    • 사용방법은 변수 타입명 뒤에 static 키워드를 기입하여 사용합니다. 
    • 해당 변수는 프로세스가 종료되기 전까지 메모리에 로드 되어 있기 때문에 과부화나 불필요하게 메모리 공간을 차지하는 것에 주의해야합니다. 
  2. 프로세스와 스레드의 차이점은 무엇인가요?
    • 프로세스 Process:
      • 실행 중인 프로그램 = 디스크에 있는 프로그램이 메모리에 적재된 상태, 운영체제의 제어를 받는 상태
      • 프로세스는 자신만의 자원을 가진다.
      • 프로세스끼리는 서로 독립적이다.
    • 스레드 Thread: 
      • 하나의 프로그램 실행 흐름 = 프로세스 내부에 존재, 프로세스는 적어도 하나의 스레드를 가진다.
      • 프로세스에 비해 필요 자원이 적다.
      • 경량 프로세스라고도 한다.
      • 스레드 간 자원을 공유한다.
  3. 스레드 세이프 (thread safe)는 무엇인가요?
    • 멀티 스레드 프로그램에서 여러 스레드가 공유 자원에 접근하여도 프로그램 실행에 있어 문제가 없는 상태를 뜻합니다. 
    • 공유 자원을 동시에 접근하게 되면 실행 순서에 따라 결과값이 달라져 데이터 불일치가 일어날 수 있습니다.  
      • 스레드 세이프를 지키는 4가지 방법
        • Mutual Exclusion 상호 배제
          • 하나의 스레드만 공유자원에 접근할 수 있도록 Mutex와 Semaphore로 Lock을 통제해주는 방법입니다. 
        • Atomic Operation 원자 연산
          • 공유 자원에 접근할 때 원자 연산을 이용하거나 '원자적'으로 정의된 접근 방법을 사용함으로써 상호 배제하는 방법이다.
          • Atomic - 공유 자원 변경에 필요한 연산을 원자적으로 분리한 뒤, 실제로 데이터의 변경이 이루어지는 시점에 Lock 을 걸고, 데이터를 변경하는 시간 동안, 다른 쓰레드의 접근이 불가능하도록 하는 방법입니다.
        • Thread-Local Storage 쓰레드 지역 저장소
          • 공유 자원의 사용을 최대한 줄이고, 각각의 쓰레드에서만 접근 가능한 저장소들을 사용함으로써 동시 접근을 막는 방법입니다.
          • 일반적으로 공유상태를 피할 수 없을 때 사용하는 방식입니다.
        • Re-Entrancy 재진입성
          • 쓰레드 호출과 상관 없이 프로그램에 문제가 없도록 작성하는 방법입니다.
  4.  경량 스레드 (virtual thread)란 무엇인가요? -- (마지막 참고자료 인용)
    • 경량 스레드는 가상 스레드라고 불리기도 하며 영문으로 light-weight thread라고도 불립니다.
    • OS 스레드를 그대로 사용하지 않고 JVM 자체적으로 내부 스케줄링을 통해서 사용할 수 있는 경량의 스레드를 제공합니다. 하나의 Java 프로세스가 수십만~ 수백만개의 스레드를 동시에 실행할 수 있게끔 설계되었습니다.
    • 개발 배경
      1. 자바의 스레드는 OS의 스레드를 기반으로 한다.
        • 자바의 전통적인 스레드는 OS 스레드를 랩핑(wrapping)한 것으로 이를 플랫폼 스레드 라고 정의한다. (자바의 전통적인 스레드=플랫폼 스레드)
        • 따라서 Java 애플리케이션에서 스레드를 사용하는 코드는 실제적으로는 OS 스레드를 이용하는 방식으로 동작했다.
        • OS 커널에서 사용할 수 있는 스레드는 갯수가 제한적이고 생성과 유지 비용이 비싸다.
        • 이 때문에 기존에 애플리케이션들은 비싼 자원인 플랫폼 스레드를 효율적으로 사용하기 위해서 스레드 풀(Thread Pool) 만들어서 사용해왔다.
      2. 처리량(throughput)의 한계
        • Spring Boot와 같은 애플리케이션의 기본적인 사용자 요청 처리 방식은 Thread Per Request 이다. 이는 하나의 request(요청)을 처리하기 위해서 하나의 스레드를 사용한다.
        • 애플리케이션에서 처리량을 늘리려면 스레드를 늘려야 하지만 스레드를 무한정 늘릴 수 없다. (OS 스레드를 무한정 늘릴 수 없기 때문)
        • 따라서 애플리케이션의 처리량(throughput)은 스레드 풀에서 감당할 수 있는 범위를 넘어서 늘어날 수 없다.
      3. Blocking으로 인한 리소스 낭비
        • Thread per Request 모델에서는 요청을 처리하는 스레드에서 IO 작업 처리할 때 Blocking 이 일어난다.
        • 이 때문에 스레드는 IO 작업이 마칠 때까지 다른 요청을 처리하지 못하고 기다려야 한다.(Blocking 동안 대기)
        • 애플리케이션에 유입되는 요청이 많지 않거나 또는 스케일 아웃으로 충분히 커버할 수 있는 정도라면 문제가 없지만,
        • 아주 많은 요청을 처리해야하는 상황이라면 Blocking 방식으로 인해 발생하는 낭비를 줄여야 할 필요가 있다.
        • 이 때문에 Blocking 이 아니라 Non-blocknig 방식의 Reactive Programming이 발전하였다.
      4. Reactive Programming의 단점
        • 처리량을 높이기 위한 방법으로 비동기 방식의 Reactive 프로그래밍이 발전해왔다.
        • 한정된 자원인 플랫폼 스레드가 Blocking 되면서 대기하는 데 소요된 스레드 자원을 Non-blocking 방식으로 변경하면서 다른 요청을 처리하는데 사용할 수 있게 되었다.
        • 대표적으로 Webflux 가 이렇게 Non-blocking으로 동작한다.
        • 다만 이런 Reactive 코드는 작성하고 이해하는 비용을 높게 만들었다. (Mono, Flux)
        • 또한 기존의 자바 프로그래밍의 패러다임은 스레드를 기반으로 하기 때문에 라이브러리들 모두 Reactive 방식에 맞게 새롭게 작성되어야 하는 문제가 있다.
      5. 자바 플랫폼의 디자인
        • 자바 플랫폼은 전통적으로 스레드를 중심으로 구성되어 있었다.
        • 스레드 호출 스택은 thread local을 사용하여 데이터와 컨텍스트를 연결하도록 설계되어 있다.
        • 이 외에도 Exception, Debugger, Profile(JFR)이 모두 스레드를 기반으로 하고 있다.
        • Reactive 스타일로 코드를 작성하면 사용자의 요청이 스레드를 넘나들면서 처리되는데, 이 때문에 컨텍스트 확인이 어려워져 결국 디버깅이 힘들어졌다.
    • 해결하고자 하는 문제
      1. Java 개발자가 하드웨어의 성능을 잘 활용하는 높은 처리량(쓰루풋)의 서버를 작성하는 것
        • 가상 스레드는 Blocking 이 발생하면 내부적으로 스케줄링을 활용하여 플랫폼 스레드가 그냥 대기하게 두지 않고 다른 가상 스레드가 작업할 수 있도록 한다.
        • 따라서 Reactive programming 의 Non-blcking 과 동일하게 플랫폼 스레드의 리소스를 낭비하지 않는다.
      2. 동시에 자바 플랫폼의 디자인과 조화를 이루는 코드를 생성할 수 있도록 하는 것
        • 기존 Reactive programming 의 장점에도 불구하고 전통적인 자바 언어의 구조는 스레드를 기반으로 하였기 때문에 Webflux등을 사용할 때 디버깅, 성능테스트가 어려웠다.
        • 하지만 가상 스레드는 기존 스레드 구조를 그대로 사용하기 때문에 디버깅, 프로파일링등 기존의 도구도 그대로 사용할 수 있다.
    • Reactive Programming 과의 비교
      • Reactive programming 이 달성하고자 하는, 리소스를 효율적으로 사용하여 높은 처리량(throughput)을 감당하려는 목적은 동일하다.
      • 가상 스레드를 사용하면 Non-blocking 에 대한 처리를 JVM 레벨에서 담당해준다.
      • 따라서 Spring Web MVC 스타일로 코드를 작성하더라도 내부에서 가상 스레드가 기존의 플랫폼 스레드를 직접 사용하는 방식보다 효율적으로 스케줄링하여 처리량을 높일 수 있다.
      • 결론적으로 가상 스레드 는 기존 스레드 방식의 이점을 누리면서도 Reactive programming의 장점을 취할 수 있다.
     

findstar.pe.kr

 

 

 

참고자료

 

[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

 

반응형