Python VS Java

데일리·2024년 11월 19일

TIL

목록 보기
9/16
post-thumbnail

현재 지금 다니는 회사에서는 서비스마다 Python과 Java를 구분해서 사용하고 있는데 이 두언어의 차이가 무엇인지 그리고 왜 이 두언어를 구분해서 사용하는지 한번 알아보자

1. 언어와 문법 스타일

우선 파이썬은 우리가 다 알다시피 간결하고 직관적이다. 이러한 특징 때문에 배우기가 쉽고 적은 코드로도 원하는 기능을 구현할 수 있다.

이에 반해 자바는 엄격하고 구조적이다. 명시적인 타입선언이 무조건적이고 객체 지향 설계로 코드가 길어지지만 명확하게 표현이 가능하다.

2. 실행 방식

파이썬은 코드를 한줄씩 읽어서 실행하는 인터프리터 방식의 언어이다. 이 방식의 장점은 아래와 같다.

  • 코드 실행과 테스트가 빠르다.(별도의 컴파일이 필요없으므로)
  • 대화형 개발환경이 가능하다(ex.아나콘다)
  • 플랫폼 독립적 실행(인터프리터만 설치되어있으면 어떤 운영체제에서도 실행 가능)
  • 코드 실행 중에 에러가 발생하면 즉시 에러를 알려준다.(자바는 컴파일 단계에서 확인 되지 않은 런타임 예외의 경우 디버깅이 복잡할 수 있다.)
  • 코드 수정 후 컴파일을 하지 않아도 즉각적인 반영 가능
  • 빠르게 프로토 타입 개발 가능

이에 반해 인터프리터가 가지고 있는 단점도 있는데

  • 느린 실행 속도(한줄 씩 해석하며 실행하므로 실행속도가 느리고 특히 CPU 집약적인 작업 및 대규모 연산에서 성능차이가 두드러진다)
    • 이유는 인터프리터가 코드를 실행 중에 해석하므로 오버헤드가 추가로 발생한다
    • GIL로 인해 병렬처리가 제한된다.
    • 위의 문제를 해결하려면 대규모 연산을 위한 라이브러리 및 모듈을 사용하거나 자체 개발하여 사용하는 경우가 많다.
  • 실행 중 에러 탐지(장점에서도 나왔지만 양날의 검이라고 볼 수 있다. 실행되기 전까지 문법에러나 타입 관련 문제가 드러나지 않기 때문에 런타임에 해당 문제가 발견된다)
  • 파이썬 스크립트를 실행하려면 인터프리터와 관련된 라이브러리가 설치되어야한다.
  • 높은 메모리 사용량(동적언어의 특성상 변수에 대한 메타데이터 정보도 저장되기 때문)
  • 병렬 처리 제약(GIL 문제)
    - 해당 문제는 아래에서 더 살펴보기로 하자

위에서는 파이썬의 실행흐름이었고 자바는 어떨까?

자바는 컴파일 방식 + JVM을 통해 실행이된다.

  • 우선 코드를 컴파일해 바이트 코드로 만들고 JVM에서 실행하는 방식이다.
  • 이 방식은 실행 속도가 빠르고 안정성이 높다.

타입 시스템

가장 대표적인 차이인 타입이다, 우선 파이썬은 동적 타임으로 어떤 변수든 데이터에 담을 수 있어 유연하다.

x = 10  # 정수
x = "Hello"  # 문자열로 변경 가능

이에 반해 자바는 변수 타임을 미리 선언하는 정적 타입으로 컴파일 단계에서 오류를 발견할 수 있다.

int x = 10;  // 정수
x = "Hello";  // 컴파일 오류 발생

병렬처리

파이썬은 GIL로 인해 단일 스레드로 밖에 실행이 되지 않는다.

여기서 GIL은 Global Interpreter Lock으로 여러 개의 스레드가 파이썬 바이트코드를 한번에 하나만 사용할 수 있게 락을 거는 것을 의미한다.

python에 GIL이 존재 이유에 대해 잠시 살펴보자면

  • python은 객체 메모리 관리를 위해 참조 카운팅을 사용한다, 그러나 여러 스레드가 참조 카운트를 동시에 수정하면 경쟁 상태가 발생할 수 있기 때문에 이를 방지하기 위해 GIL(Global Interperter Lock)을 사용해 단일 스레드로만 수행되게 하는 것이다.
obj = []       # 참조 카운트 1
ref = obj       # 참조 카운트 2
del obj         # 참조 카운트 1
del ref         # 참조 카운트 0 -> 메모리 해제

위 처럼 참조 카운트 방식으로 설정된 ref가 기존 변수인 obj 데이터를 삭제하니 ref 데이터도 삭제된 것을 볼 수 있다. 해당 문제가 멀티 스레드 방식을 지원할 경우 발생할 수 있기 때문에 GIL이 필요한 것이다.

따라서 파이썬은 해결하기 위해 멀티스레드 대신 멀티 프로세싱 모듈로 분리해 병렬성을 높이는 방식을 사용한다.

그렇다면 Java에서도 참조 카운팅 방식인데 왜 자바는 멀티 스레드가 될까?? 라는 질문이 나올 수 있다.

이는 Java의 메모리 관리가 파이썬과 다르기 때문이다. 자바에서는 참조 카운팅만 사용하는 것이 아니라 트리버설 방식을 사용하는데 이는 참조 카운트를 유지하지 않고 도달 가능성 분석을 통해 사용 하지 않는 객체를 식별하는 것이다.

이를 바탕으로 자바는 참조 카운트를 사용은 하지만 실시간 참조 카운팅을 사용하지 ㅇ낳고 도달 가능성 분석을 기반으로 참조 유형을 조합해 사용한다.

또한 동시성 문제를 방지하기 위해 Java의 가지비 컬렉터는 내부적으로 필요한 경우에 락이나 메모리 모델을 사용해 안전하게 작업하기 때문에 Java는 GIL로 부터 벗어날 수 있다.

특징pythonjava
카비지 컬렉션 방식참조 카운팅 + 주기적인 GC실시간 참조 카운팅X, 도달 가능성 분석
참조 카운팅 사용 여뷰OX
동시성 관리(GIL)GIL로 한번의 쓰레드만 실행GIL없음, 멀티 쓰레드 병렬 실행 지원
가비지 컬렉션 성능단일 스레드 위주로 동작병렬 GC 및 고성능 GC 옵션
스레드 안전성GIL로 참조 카운팅 동기화 문제 해결메모리 모델로 객체 참조 변경을 안전하게 관리

가비지 컬렉션

👉🏻 파이썬의 가비지 컬렉션
파이썬 가비지 컬력션은 참조 카운팅과 사이클 검출 이 두가지 방식으로 메모리를 관리한다.
1. 참조 카운팅

  • 객체가 참조 될때마다 카운터를 증가시키고 참조가 없어지면 감소시킨다.
  • 카운터가 0이 되면 해당 객체는 즉시 메모리에서 해제
a = [1, 2, 3]  # 리스트 객체 생성, 참조 카운트 = 1
b = a           # 참조 카운트 증가 = 2
del a           # 참조 카운트 감소 = 1
del b           # 참조 카운트 = 0 -> 메모리에서 삭제
  1. 사이클 검출
  • 참조 카운트만으로는 순환 참조(두 객체가 서로를 참조하여 참조 카운트가 0이되지 않는 경우)를 해결하지 못함
  • 파이썬은 GC 모듈을 사용해 주기적으로 힙메모리를 검사하고 순환 참조를 제거한다.

장점

  • 참조 카운팅 덕분에 가비지 컬렉션이 즉시 발생한다(빠른 해제)
  • 단순한 프로그램에서 성능이 뛰어난다.

단점

  • 순환 참조가 있는 경우 추가로 사이클 검출 과정을 거쳐야 해서 성능이 떨어질 수 있다.
  • 복잡한 객체 그래프에서 메모리 누수 가능성이 있음
  • 참조 카운팅과 GC 작업이 동시에 일어나면 성능에 영향을 줄 수 있다.

👉🏻 자바의 가비지 컬렉션
자바의 가비지 컬렉션의 주요 특징은 아래와 같다

  • JVM이 가비지 컬렉션을 관리하며 다양한 GC 알고리즘을 제공
  • Generational GC(세대별 GC)방식을 사용

작동 방식
1. 세대별 메모리 관리

  • JVM은 힙 메모리를 세개의 영역을 나눈다.
    • Young Generation: 새롭게 생성된 객체가 저장
    • Old Generation: 오래 살아남은 객체가 저장'
    • Permanent Generation(Metaspace): 클래스 메타데이터 같은 구조적 정보가 저장
  • 객체는 Young Generation -> Old Generation으로 이동하며 GC 빈도는 Young에서 더 많이 발생한다.
  1. GC 알고리즘
  • 자바는 여러 GC알고리즘을 지원하며 개발자가 목적에 따라 선택할 수 있다.
    • Serial GC: 단일 스레드로 GC를 수행(간단하지만 느림)
    • Parallel GC: 여러 스레드를 사용해 GC를 병렬로 수행(대규모 애플리케이션에 적합)
    • G1 GC: 최신 GC로 큰 힙 메모리르 효율적으로 관리(지연 시간 감소)
    • ZSC, Shenandoah GC: 낮은 지연 시간을 목표로 설계된 최신 GC
  1. Stop-the-world

    • GC 중 JVM은 일시적으로 모든 애플리케이션 스레드를 멈추는 STW 이벤트를 발생시킨다.
    • 최신 알고리즘은 STW 시간을 최소화하기 위해 설계되었거나 병렬/동시 GC를 통해 STW 없어도 메모리를 관리할 수 있도록 발전

장점

  • JVM이 가비지 컬렉션을 자동으로 최적화하므로 개발자가 메모리 관리에 크게 신경쓰지 않아도 된다.
  • 다양한 GC 알고리즘을 제공하여 애플리케이션의 요구사항에 따라 조정 가능

단점

  • STW 이벤트로 인해 응답시간이 길어질 수 있다.
  • 복잡한 설정과 튜닝이 필요할 수 있다.
특징pythonjava
메모리 관리 방식참조 카운팅 + 순환 참조 검출세대별 GC + 다양한 알고리즘
즉시 객체 해제 여부참조 카운팅으로 즉시 해제GC가 실행될 때까지 객체가 메모리에서 유지
GC 방식주로 단일 스레드병렬 및 병합 가능한 다양한 알고리즘 지원
성능소규모 애플리케이션에 적합. 순환 참조 검출 시 성능 저하대규모 애플리케이션에서 뛰어난 성능과 확장성 제공
병럴처리GC가 단일 스레드로 동작병렬 GC를 통해 멀티코어를 활용한 효율적인 메모리 관리 기능
튜닝 가능성제한적JVM 옵션을 통해 GC 동작을 세부적으로 튜닝 가능

결과적으로...

파이썬은 인터프리터의 특징 및 병렬 처리의 문제로 대규모 프로젝트일 경우 성능 이슈가 발생할 수 있기 때문에 소규모 프로젝트 및 머신 러닝, 데이터 분석에 강하다.

반면에 자바는 엄격한 문법 덕분인지 안정적이고 튼튼하고 병렬처리와 뛰어난 GC 성능으로 인해 대규모 프로젝트에 강한 것을 볼 수 있었다.

이렇게 까지 자세히 포스팅을 할 계획은 없었지만 파면 팔수록 두언어 모두 각기 다른 특징을 지니고 있어 각자 다른 매력을 발견하면서 글이 길어지고 말았다..... 그럼 오늘 포스팅은 여기까지

profile
하루에 한편 씩 읽기 좋은 테크 로그

0개의 댓글