일단 씻고 나가자
24.08.14 본문
2024. 08. 14 수요일
- [Java] 가비지 컬렉션의 원리, 동작 방식?
: 가비지 컬렉션은 Heap 메모리에 올라온, 사용하지 않는 객체를 주기적으로 지워 메모리를 비우는 방식으로, stack에 주솟값이 존재하지 않는, 활용하지 않는 객체(Unreachable)를 지운다. 이렇게 GC가 작동하는 동안 JVM은 프로그램 실행을 멈추는데 이를 STW(Stop The World)라 한다.
GC가 메모리를 비우는 알고리즘을 Mark and Sweep이라 하는데,
GC root에 연결된 객체를 탐색하며 연결된 객체에 마크를 남기는 것을 Mark 과정,
마크가 남겨져 있지 않은 Unreachable 객체를 지우는 것을 Sweep 과정,
GC에 따라 분산된 객체를 Heap의 시작 지점으로 모으는 것을 Compact 과정이라 한다.
기존의 방식은 mark를 남기는 것 대신 연결된 객체에 count를 +1씩 더해서 판별하였는데, 이는 순환 참조 문제를 해결하지 못한다.
GC는 대상이 되는 지점인 Heap을 Young/Old generation 영역으로 설계하여 관리하며,
Young generation의 경우 또 Eden + survival 0 + sruvival 1 영역으로 나뉜다.
1. 새로 생성되는 객체는 Eden(Young Generation)에 저장.
2. Eden이 가득 차면 Mark and Sweep(Minor GC) 과정을 거치며,
3. Reachable 객체는 survival 0 혹은 survival 1 둘 중 이미 활용하고 있는 공간으로 이동.
(항상 둘 중 이전에 활용했던 부분만 활용하게 되며, 따라서 둘 중 하나는 항상 비어 있음)
+) 이때 Reachable로 판별되어 다른 공간으로 이동할 때 객체의 age 값을 1 증가시킴.
4. survival이 가득 차면 다른 survival로 이동하며 반복.
5. JVM에 따라 한계치 age가 됐을 경우 Old generation 영역으로 이동.
6. Old generation이 가득 찼을 경우 Mark and Sweep(Major/Full GC) 과정 수행.
이런 순서로 수행하는데, Minor GC의 경우 공간이 좁기에 수행 시간이 0.5 ~ 1초 사이로 짧지만, Major GC의 경우 10배 이상의 수행 시간이 소요된다. 이때는 thread가 멈추고 CPU에 부하를 주어 STW 문제가 대두된다.
- 누적합 알고리즘?
: 누적합 알고리즘이란 특정 범위의 index를 다수 탐색하며 합 연산을 수행할 때, O(n * m)의 수행 속도를 O(1) 속도로 단축하는 알고리즘이다. 탐색하려는 배열의 크기만큼 여분 배열이 필요하다.
만약 기존 배열을 arr[], 같은 크기만큼의 여분 배열을 temp[]라 했을 때,
index a부터 b까지 n만큼 더하는 경우 temp[a] += n, temp[b+1] -= n 두 정보만 넣는 것으로 누적합 알고리즘 준비는 완성된다.
이후 모든 정보를 저장한 후에 for(i -> 1 ~ temp.length) temp[i] += temp[i-1]를 수행하고,
동일 index의 temp 값을 기존 arr 배열 값에 더해주면 최종값이 출력된다.
이차원 배열의 경우 (a1, a2)에서 (b1, b2) 범위에 n을 더한다면
temp[a1][a2] += n, temp[b1+1][b2+1] += n, temp[a1][b2+1] += -n, temp[b1+1][a2] += -n
정보를 추가하고 이후 가로, 세로 (순서는 상관없음) temp[i] += temp[i-1] 수행을 통해 최종 temp 배열을 출력할 수 있다.
- [Java] transient 키워드?
: 직렬화에 포함하지 않을 변수에 선언한다. password와 같이 보안상 유의해야 할 곳, 혹은 굳이 저장하지 않아도 될 변수에 활용한다. 비슷하게 static 키워드의 경우 선언과 동시에 초기화되기 때문에 직렬화에 포함되지 않는다.
OutputStream의 getDefaultSerialFields() 메서드는 직렬화를 담당하는데, 내부적으로 for문을 돌며 transient 혹은 static이 선언된 필드는 list에 담지 않는다.
- [Java] close()의 이유?
: InputStream 등의 객체들은 close()를 제공하는 경우가 많다.
이의 사용 이유는 사용하고 있는 외부 자원 (XXXStream 류의 경우 OS를 통해 자바 외적인 곳에서 데이터를 받기에)의 연결을 종료하고 자원을 반납하여 코드의 꼬임을 방지하는 차원과,
close()로 객체의 사용 종료를 명시하지 않을 시, GC는 해당 객체가 사용 중이지는 않지만 그렇다고 종료한 것도 아니라는 판단에 메모리를 비우지 않는 문제의 방지에 활용된다.