Java에 대해서

조현근·2022년 12월 16일
0
post-thumbnail

Java의 장점과 단점

장점

  • JVM 위에서 동작하기 때문에 OS에 독립적이다.
  • GC가 메모리를 관리해주기 때문에 편리하다.

단점

  • JVM 위에서 동작하기 때문에 실행 속도가 상대적으로 느리다.
  • 다중 상속이나 타입에 엄격하는 등 제약이 있는 것이 많다.

싱글톤 패턴

Java로 싱글톤 패턴을 구현하면 다음과 같은 단점이 발생한다.

  • private 생성자를 갖고 있어 상속이 불가능하다.
  • 테스트하기 힘들다.
  • 서버 환경에선 싱글톤이 1개만 생성됨을 보장하지 못한다.
  • 전역 상태를 만들 수 있기 때문에 바람직하지 못하다.

1. private 생성자를 갖고 있어 상속이 불가능하다.

싱글톤은 자신만이 객체를 생성할 수 있도록 생성자를 private으로 제한한다. 하지만 상속을 통해 다형성을 적용하기 위해선 다른 기본 생성자가 필요하므로 객체지향의 장점을 적용할 수 없다. 또한 싱글톤을 구현하기 위해선 객체지향적이지 못한 static 필드와 static 메서드를 사용해야 한다.

2. 테스트하기 힘들다.

싱글톤은 static으로 한번 할당되면 보통 프로그램이 종료되기 전까지 계속 살아있게 된다. 테스트는 독립적이여야 하는데 싱글톤은 한번 만들어지면 계속 사용됨으로 다른 테스트에도 계속 영향을 주게되는 문제가 있다.
private 생성자만 가지고 있어 동적으로 재할당 할 수도 없고 fake 객체를 만드는 것 또한 불가능해 테스트하기가 까다롭다.

3. 서버 환경에선 싱글톤이 1개만 생성됨을 보장하지 못한다.

서버에서 클래스 로더를 어떻게 구성하느냐에 따라 1개 이상의 객체가 만들어질 수 있다. 또한 여러 개의 JVM에 분산돼서 설치되는 경우에도 독립적으로 객체가 생성된다.(아직 잘 이해가 되지 않음)

4. 전역 상태를 만들 수 있기 때문에 바람직하지 못하다.

싱글톤의 스태틱 메소드를 이용하면 언제든지 해당 객체를 사용할 수 있고, 전역 상태로 사용되기 쉽다. 아무 객체나 자유롭게 접근하고 수정하고 공유하게 되면 의존성이 높아지게 되어 변경에 취약하게 된다.

JIT 컴파일러란?

  • Just-In-Time의 약자다.
  • "동적 변환(dynamic traslation)"이라고 보면 된다.
  • JIT은 프로그램 실행을 보다 빠르게 하기 위해서 만들어졌다.
  • 명칭은 컴파일러지만, 실행시에 적용되는 기술이다.
  • 인터프리트 방식과 정적 컴파일 방식을 혼합한 방식이다.
  • javac라는 명령어를 사용해 만들어지는 class파일은 바이트 코드이다.
  • 이 바이트 코드를 컴퓨터에서 실행하기 위해선 다시 변환 작업이 필요하다. 이 변환 작업을 JIT 컴파일러에서 한다.
  • 변환작업은 지속적으로 이루어지고, 필요한 코드의 정보는 캐시에 담아두었다가 재사용하게 된다.
  • JIT을 사용하면 반복적으로 수행되는 코드는 매우 빠른 성능을 보인다는 장점이 있지만 반대로 처음에 시작할 때는 변환 단계를 거쳐야 하므로 성능이 느리다는 단점이 있다.
  • 하지만 CPU 성능이 많이 좋아지고 JDK 성능 개선도 많이 이루어져 이런 단점들이 많이 개선되었다.

JVM

JVM은 작성한 자바 프로그램이 수행되는 프로세스를 의미한다. Java라는 명령어를 통해 애플리케이션이 수행되면, 이 JVM 위에서 애플리케이션이 동작한다. JVM에서 작성한 프로그램을 찾고 실행하는 일련의 작업이 진행된다.
자바의 메모리 관리는 JVM의 GC에서 해주기 때문에 개발자가 따로 하지 않아도 된다.

Class Loader System으로 class 파일을 읽어옴

Hello.java 라는 파일을 $javac 명령어로 compile하면 hello.class라는 파일이 만들어지고, $java 명령어로 hello를 실행하면 JVM은 class loader를 통해 class 파일을 읽어드림
클래스 파일에는 클래스에 대한 모든 정보가 들어있음

class loader는 class파일 정보를 메모리에 올리고 검증하고 static 변수를 초기화하는 역할을 함

Runtime Data Areas

JVM이란 가상머신이 사용하는 메모리 공간. class 파일이 class loader에 의해 method area에 올라간다.

class파일 안엔 바이트코드가 있음. 이는 JVM이 이해할 수 있는 명령어 집합.
JVM은 바이트코드를 기계어로 변역해 cpu에게 일을 시키는 것. 바이트코드를 기계어로 변역하는 것을 interpreter가 수행하게 됨(어떤 경우엔 interpreter가, 어떤 경우엔 JIT이 수행한다고 들음..).

Runtime Data Area

runtime data area에 대해 중점적으로 살펴보자.

런타임 데이터 영역은 JVM 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역이다.

[메서드 영역]
클래스에 대한 모든 정보가 저장됨.

  • 클래스 멤버 변수의 이름(메서드 밖, 클래스에 선언된 변수의 이름)
  • 데이터 타입
  • 접근 제어자 정보와 같은 각종 필드 정보들과 메서드 정보
  • 데이터 type 정보
  • constant pool
  • static 변수
  • final class등이 생성되는 영역

[힙 영역]
런타임에 생성되는 모든 객체들이 저장됨.

  • new 키워드로 생성된 객체와 배열이 생성되는 영역
  • 주기적으로 GC가 제거하는 영역

[스택 영역]
메서드를 실행하기 위한 정보들이 저장됨. Frame이란 자료구조가 들어가는데 메서드가 하나 호출될때마다 새로 생기고 메서드가 끝나거나 예외가 터지면 사라짐.

public class Crew {
	
    public static void main(String[] args) {
    	Crew crewObj = new Crew();
        crewObj.methodA(3);
    }
    
    private int methodA(int param) {
    	int localVariable = 1;
        int sum = localVariable + param;
        methodB();
        return sum;
    }
    
    private void methodB() {
    
    }
}

위 코드가 실행되고 methodB()까지 호출된다면 아래와 같이 frame이 쌓이게 된다.

methodA의 frame을 자세히 들여다보자

우선 local variables array와 operand stack에 대해 집중적으로 알아보자.
위 코드 methodA를 보면 param이라는 매개변수와 localVariable, sum이라는 지역변수가 있음
JVM은 stack기반으로 연산을 수행하는데 피연산값 혹은 연산의 중간값을 저장하기 위해 operand stack을 사용함

이제 methodA가 수행되면서 어떻게 operand stack이 사용되는지 살펴보자
(테코톡에 있는 바이트코드는 생략했습니다.)

만약 정수가 아니라 객체라면 heap에 저장된 객체 참조값을 지역변수 배열에서 사용함

[PC 레지스터]
현재 실행되고 있는 명령의 주소를 저장하고 있음
멀티스레드 프로그래밍 환경에서 한 스레드가 작업을 하다가 컨텍스트 스위칭이 일어나고 다시 돌아오면 이전에 어떤 명령을 수행하고 있었는지 알고 있어야 하기 때문에 존재함.

[네이티브 메서드 스택]

  • 자바 이외의 언어(C, C++, 어셈블리)로 작성된 네이티브 코드를 실행할 때 사용되는 메모리 영역, 일반적으로 C 스택을 사용

[Current class constant pool reference]

class 파일안에 어떤 정보가 들어있는지 우선 알아보자.
이를 알아보기 위한 샘플 코드이다.

package com.example;

public class Wooteco {
	public static void main(String[] args) {
    	Crew crew = new Crew();
        crew.study();
    }
}
package com.example;

public class Crew {
	private int level = 2;
    
    public void study() {
    
    }
}

(어썸오의 테코톡을 봤는데 아직 이해가 되지 않는다 나중에 다시 정리하겠다)

GC (Garbage Collector)

JVM은 다음과 같은 영역을 나누어 힙이라는 공간에 객체들을 관리한다(JDK 벤더마다 조금씩 상이하며 오라클에서 제공하는 JDK 기준으로 설명하겠다).

  1. Heap 영역에서 동적으로 할당된 객체 중 불필요한 객체를 찾는다.
  2. 찾아낸 garbage를 처리해서 메모리를 해제한다.

불필요한 객체(Garbage)란?

  • 유요한 참조가 존재하는 객체는 Reachable 상태
  • 그렇지 않으면 Unreachable 상태
  • Root set과의 관계로 Reachable, Unreachable을 구분한다.
    • Root Set과 참조 관계가 있으면 Reachable
    • Root Set과 어떤 관계도 없으면 Unreachable
  • Root Set
    • Stack 영역의 지역 변수, 파라미터
    • Method 영역의 정적 변수
    • JNI에 의해 생성된 객체

GC 동작 방법

  1. Root set으로부터 Heap 영역의 모든 객체를 스캔하여 Reachable한 객체를 찾는다. -> Mark 과정이라 함
  2. Unreachable한 객체를 Heap 영역에서 제거한다. -> Sweep 과정

Heap 메모리 구조를 나누어 관리하는 이유

  1. 하나의 메모리 영역으로 관리하면 모든 객체를 하나하나 추적하는 것은 시간이 오래걸리고 부하가 발생할 수 있는 작업
  2. Weak generational hypothesis
    • 대부분 할당된 객체는 오랫동안 참조되지 않으며 금방 Garbage 대상이 된다.
    • 오래된 객체에서 젊은 객체로의 참조는 거의 없다.

GC는 언제 발생할까?

Minor GC: young generation에서 발생하는 GC
Major GC: Old generation에서 발생하는 GC

Young generation

Eden: 새로운 객체가 저장되는 영역
Survivor: 에덴 영역에서 살아남은 객체가 저장되는 영역. 두 survivor 영역 중 하나는 항상 비워져있다.

Eden영역에 가득차면 Mark and Sweep 과정이 일어나고 Unreachable한 객체를 해제한다. 살아남은 객체는 survivor영역으로 옮겨진다. survivor 영역으로 옮겨지는 과정을 Stop and Copy라고 한다.
survivor 영역으로 옮겨진 객체는 age가 1 증가한다.

Eden영역이 가득 차 Stop and copy 과정이 일어나면 Eden영역의 유효한 객체 뿐만아니라 survivor 영역의 객체들도 또 다른 survivor 영역으로 옮겨진다(하나의 survivor 영역은 항상 비워지게 된다).
이런 과정속에서 살아남는 객체들은 계속 age가 1씩 증가하게 된다.

객체의 age가 특정 임계값을 넘게되면(HotSpot JVM default 임계값은 31) 해당 객체들은 old generation 영역으로 이동시킨다. 이를 promotion이라고 함.

Old generation

old generation 영역에 객체가 가득차게되면 이때 Major GC가 일어나게 됨

young

말 그대로 젊은 객체들이 존재한다.
Eden과 survivor 영역으로 나뉘는데, 객체를 생성하자마자 저장되는 장소는 eden이다.
일반적으로 아래와 같은 과정으로 메모리에 유지된다.
1. Eden 영역에서 객체가 생성된다.
2. Eden 영역이 꽉 차면 살아있는 객체만 survivor 영역으로 복사되고, 다시 eden 영역을 채우게 된다.
3. survivor 영역이 꽉 차게 되면 다른 survivor 영역으로 객체가 복사된다. 이때 eden 영역에 있는 객체들 중 살아있는 객체들도 다른 survivor 영역으로 간다. 즉, survivor 영역의 둘 중 하나는 반드시 비어 있어야만 한다.

출처
https://mangkyu.tistory.com/94
https://mangkyu.tistory.com/151
https://mangkyu.tistory.com/153
https://blog.hexabrain.net/394
자바의 신 2권
https://coding-factory.tistory.com/828
https://www.youtube.com/watch?v=GU254H0N93Y
https://www.youtube.com/watch?v=8JrciOSL3Gk

profile
안녕하세요!

0개의 댓글