: C나 C++에서는 코드 레벨에서 메모리를 할당 받고, 해제해야 한다.
자칫 실수하면 메모리 누수가 발생
수종으로 메모리를 관리하면 번거롭고 어렵다.
하지만, java에서는 GC가 Heap 메모리에서 unreachable한 객체를 삭제 시켜준다. 코드레벨의 메모리 관리에서 벗어나 편리하다.
메모리 누수가 발생하지 않음
휴먼 에서 가능성 낮춤 (해제된 메모리 접근, 메모리 이중해제)
성능 저하
: 어떤 메모리를 해제해야 할지 검사하고 삭제하는 이 과정 또한 결국 CPU자원과 메모리를 필요로 한다.
대규모 데이터가 있을수록 비용은 더 증가
개발자는 언제 메모리가 해제되는지 모른다.
: jvm은 GC를 실행시키기 위해 잠시 Application 실행을 멈춘다.
실시간 성이 매우 강조된다면, 이런 특징이 적합하지 않을 수 있다.
: root set으로부터 Heap 영역의 모든 객체를 스캔
: root set에서 unreachable 한 객체를 Heap 영역에서 제거
의도적으로 GC를 실행시켜야한다.
: jvm에겐 "이쯤 되면 GC 실행시켜야지" 라는 나름의 기준이 존재한다.
이 기준을 알기 위해선 jvm의 heap 영역을 알아야한다.
application 실행과 GC 실행이 병행된다.
young, old generation으로 나뉨 (CG도 이를 기준으로 나뉨)
young generation: 새로운 객체들이 할당
old genaration: young generation 에서 오랫동안 살아남은 객체들이 존재
할당된 객체는 오랫동안 참조되지 않는게 대부분이다. (금방 garbage 상태가 된다.)
반대로 오래된 객체에서 젊은 객체로의 참조는 거의 없다.
따라서 heap이 하나라면 오래된 객체까지 스캔해서 비효율적이다.
차라리 나눠 오래된 객체는 따로 빼두고 할당되지 얼마 안 된 객체들만 주기적으로 스캔하는게 훨씬 효율적
: 여기서 발생하는 GC 는 major GC로 minor GC 보다 더 오래 걸린다. ( young generation 마친가지로 꽉차면 mark and sweep 이 진행
사실 완전히 같이 실행되는 건 아니다.
JVM은 GC를 실행하기 위해 Application 실행을 멈춘다. = step the world
이 step the world 시간이 짧을수록 최적화 된 것이다.
여러 방식이 있는데 자주 쓰이는 것만 소개를 한다.(parallel, G1)