Java Jvm
title: “[Java]JVM과 GC란 무엇인가?” date: 2019-05-21 15:05:28 -0400 categories: jekyll update —
Java
- volatile(참고)
- 인터페이스와 추상클래스의 차이? 일반적으로 추상클래스는 그것을 베이스 클래스로 상속해서 더 구체적인 클래스를 만들어서 쓰는 경우에 쓰기 좋다. 특히 서브클래스에서 써먹을 수 있는 공통적인 기능을 추상 베이스 클래스에 집어넣을 필요가 있을 때 좋다. 서로 관련이 없는 클래스에서 개념적으로 연관된 기능을 작동시킬 수 있는 공통된 방식이 필요하지만 그 기능을 구현하는 방법은 제각기 다른 경우에는 인터페이스가 좋다.
- try-with-resources 란?
Java7 부터 AutoCloseable를 구현한 클래스는 자원 종료를 명시적으로 하지 않아도 되게 해준다.
try(final FileReader reader = new FileReader("/tmp/dataFile")){ final char[] buffer = new char[128]; reader.read(buffer); } catch (IOException e) { // 예외 처리 }
- String
- 인터닝(interning) 이란?
클래스가 JVM에 로드되면 모든 리터럴이 상수 풀에 위치하게 된다.
그리고 String 리터럴의 모든 반복은 풀 안의 같은 상수를 참조해서 이루어지는데, 이를
String 인터닝
이라고 한다. String 인턴 풀은 컴파일할 때 단지 String 리터럴을 가져오는 게 아니라 intern 메소드를 이용해서 모든 String 인스턴스를 이 풀에 추가한다.
- 인터닝(interning) 이란?
클래스가 JVM에 로드되면 모든 리터럴이 상수 풀에 위치하게 된다.
그리고 String 리터럴의 모든 반복은 풀 안의 같은 상수를 참조해서 이루어지는데, 이를
- 제네릭
매개변수화된 타입
이라고도 알려져 있다. 컬렉션 클래스에서 제네릭을 사용했을 때, 컴파일러는 특정 타입만 포함될 수 있게 컬렉션을 제한한다. 실행할 때 발생할 수 있는 잠재적인 모든 예외가 실제 컴파일러 에러로 이어진다. 이러한 예외는 개발 수명 주기에서 훨씬 빨리 발견되어 코드를 신속하게 수정하고 정리할 수 있게 해준다. - StringBuffer 와 StringBuilder 의 차이점은?
StringBuffer 는 변경 가능하지만
thread-safe
하다. 반면 StringBuilder 는 synchronization 이 적용되어 있지 않아서thread-safe
하지 않는다. - Class objects?
- main 메소드가 static 인 이유?
- Object Class
- Why not static? static 은 객체지향적이지 않다. static 변수는 프로그램이 실행되고 있는 내내 살아있게 된다. 즉, 그 클래스를 이용한 작업을 끝내더라도 static 변수가 점유하고 있는 메모리는 GC에 의해 회수되지 않게 된다. static 은 재사용성이 떨어진다. ; static 메소드는 인터페이스를 구현하는데 사용할 수 없다.(객체지향을 방해함) static variable 로 참조되는 객체는 GC 되지 않는가? 그렇지 않다. static variable을 갖는 클래스 자체가 참조되지 않는다면 GC의 대상이 된다. 그렇다면 언제 클래스 자체가 참조되지 않게 될까? if the application (or framework) dynamically creates a classloader, dynamically loads classes
- JVM 클래스 로더가 클래스를 메모리에 로드하면 JVM은 바이트코드가 유효한지 검증한다. 검증하고 나면 JVM은 코드가 실행되는 아키텍처와 운영체제에 맞는 명령어로 바이트코드를 해석할 수 있다. 하지만, 이는 처리 시간이 오래 걸릴 수 있고, 일부 초기 JVM에서는 실제로 그랬다고 한다.(특히 GUI 작업에서…) JIT 컴파일러는 동적으로 실행 중인 바이트 코드를 명령어로 변환한다. 그래서 바이트코드를 번역할 필요가 없다. 이렇게 동적으로 실행되면 JIT은 실행되는 동안 애플리케이션의 상태에 따라 높은 최적화 수준을 가진 머신코드를 만들 수 있다.
Java GC
- JVM Memory types
-
Heap Memory new 키워드는 자바 heap 영역에 메모리를 할당한다. 힙은 애플리케이션 영역에 접근할 수 있는 메모리의 메인 영역이다. 힙은 generation 이라는 몇 가지 영역으로 구분된다. 가비지 컬렉션에서 객체가 수집 대상에서 제외된다면 다른 generation으로 옮겨진다. 클래스 인스턴스와 배열들은 heap 메모리에 저장된다. Shared memory 라고 불린다. 여러 스레드들이 동일한 데이터를 공유하는 장소이기 때문이다.
- Non-heap Memory
- Method Area
per-class structure(
런타임 상수
와static field
를 의미함.),메소드와 생성자에 대한 코드
가 저장된다.
- Method Area
per-class structure(
-
Memory Pool heap 이나 non-heap에 속할 수 있다.
-
Runtime Constant Pool 클래스 파일 안에 있는 상수 풀 테이블에 대한 per-class / per-interface run time representation 이다. 각각의
Runtime Constant Pool
은Method area
에 할당된다. - Java Stack
스레드 전용으로 생성된다. 모든 스레드는 PC와 Java Stack을 갖는다.
PC는
java stack
을intermediate values
,dynamic linking
,return values for methods and dispatch exception
을 저장하는데 사용한다.
-
- Memory Generations(Young + Old generation) : Heap은 generation이라는 몇 가지 영역으로 구분된다.
- Young Generation
- Eden
짧은 기간 동안 살아있는 객체들은
Eden space
에서 이용할 수 있다. 모든 객체들은Eden space
에서 생명주기가 시작된다. GC가 일어날 때 객체가 여전히 alive 하면Survivor space
로 이동된다. 참조되지 않는 객체들은 제거된다. - Survivor
- Eden
짧은 기간 동안 살아있는 객체들은
- Old Generation(Tenured + PermGen)
- Tenured: GC는
Survivor space
로부터 살아있는 객체들을tenured generation
으로 이동신킨다.
- Tenured: GC는
- PermGen:
VM, class, method objects에 대한 메타데이터를 포함한다.
일반적으로 클래스 정의나 String 상수 같이 JVM에서 실행되는데 필요한 불변(immutable) 상태가 포함된다.
Java 7 부터 String constant poll의 위치는 Heap 영역으로 변경되었다.(출처1)
PermGen 은 고정된 사이즈고 런타임에 사이즈가 확장되지 않는다. 따라서 Java 6 까지는 String의 intern() 메소드 호출은 OOM을 발생 시킬 수 있어서 거의 사용하지 않는 것이 맞다.
Heap 영역으로 String constant poll의 위치가 변경됨으로써 문자열도 GC의 대상이 될 수 있게 되었다.(참조 카운트로 따짐)
Java 8에서
PermGen
은 물리 메모리에 위치할Metaspace
라는 새로운 영역으로 변경되었다.PermGen
은 Java Heap 이었던 적이 없다. 단지 Java Heap 에 연속된 메모리 공간에 할당되어있을 뿐이다. 하지만Metaspace
로 바뀌면서 이런 연속된 메모리 할당은 존재하지 않게 되었다.Metaspace
는 운영체제의native memory
에 할당된다.(출처2, 출처)
- Young Generation
-
가비지 컬렉션이란 무엇인가? 프로그래밍 언어에서 효율을 높이기 위해 메모리를 자동으로 관리하는 시스템이다.
-
가비지 컬렉션 알고리즘? 더 이상 참조되지 않는 메모리를 찾은 후 메모리를 할당할 때 이용할 수 있도록 반환한다는 공통의 목적이 있다. 전통적인 GC는
mark-and-sweep
방식이라고 한다. 실행 중인 코드에서 참조하는 객체는 live로 표시되며 해당 객체에서 참조하는 것들 역시 확인해서 live로 표시한다. 이는 현재 동작하는 객체의 모든 경로가 확인될 때까지 계속된다. 이 과정이 끝나면 Heap에 있는 각 객체들을 찾아다니며 live로 표시되지 않은 메모리 위치에 메모리를 할당할 수 있게 만든다. 과정이 진행되는 동안에는 메모리를 재배치 하려고 JVM의 모든 스레드가 정지되는데, 이를stop-the-world
라고 한다. GC는 이 작업에 소요되는 시간을 최소화하려고 노력한다. Why does the JVM full GC need to stop-the-world? 결국 가비지 컬렉션은 다른 generation으로의 이동과 가능한 한 많은 여유 공간을 남겨두려는 목적으로, 메모리에서 객체들을 옮기고 자주 접근되는 객체들을 묶어두는 등의 다른 연산을 수행한다.(Compaction
이라고 한다) - 5가지 reachability(출처3)
- strongly reachable
- softly reachable 오직 SoftReference 객체로만 참조된 객체는 Heap에 남아 있는 메모리의 크기와 해당 객체의 사용 빈도에 따라 GC 여부가 결정된다.
- weakly reachable GC를 수행할 때마다 회수 대상이 된다.
- phantomly reachable GC 대상 여부를 결정하는 부분에 관여하는 softly, weakly 와는 달리 phantomly 는 파이널라이즈와 메모리 회수 사이에 관여한다. finalize 되었지만 아직 메모리가 회수되지 않은 상태이다. 파이널라이즈 이후에 처리해야 하는 리소스 정리 등의 작업이 있다면 유용하게 사용할 수 있다.
- unreachable root set으로부터 시작되는 참조 사슬로 참조되지 않는 객체
-
GC 대상인 객체를 찾는 작업
과GC 대상인 객체를 처리
하여메모리를 회수하는 작업
은 즉각적인 연속 작업이 아니다. GC 대상 객체의 메모리를 한 번에 모두 회수하지도 않는다. - GC 대상 객체를 처리하는 작업(finalize)과 할당된 메모리를 회수하는 작업도 연속된 작업이 아니다.
-