오늘은 어제 프갤에 나왔던 면접 질문 답변해보기.
1. 유저레벨 스레드와 커널레벨 스레드를 비교하여 설명하세요.
유저레벨 스레드 :
- 커널영역 쓰레드와 하나의 프로세스가 엮이는 구조. (라이브러리 사용해서 쓰레드 생성하는 방식임 pcreate)
- OS는 프로세스 안에 많은 쓰레드가 있는지 모름. 그냥 한개의 쓰레드가 있겠지 하고 연결..
장점 : OS 시스템 콜 활용안해서 오버헤드 적음.
단점 :
- 한개의 쓰레드가 락걸면 전체 프로세스 스탑됨. 예를들어 join() 부르면 끝날때까지 머기타야됨.
- 멀티프로세서 버프 못받음.
커널레벨 쓰레드:
- 커널영역 쓰레드와 각각의 쓰레드가 엮이는 구조.
장점 : 멀티 프로세서 이점 받음. 스케줄링 독립적으로 수행되므로, 한개 락걸려서 멈춰도 다른 쓰레드 스케줄링됨.
단점 : 오버헤드 문제. OS는 쓰레드의 스케일까지 고려해야함.
2. 퀵소트가 왜 머지소트보다 빠를까요?
Locality의 이점을 활용하는 퀵소트가 더 빠름.
머지소트는 전체적으로 순회하면서 정렬하고
퀵소트는 국소범위를 정하고 순회하면서 정렬함.
3. 알고있는 GC와 작동 방식.
Java의 GC
1. GC Root이 있음. (GC root는 힙 영역 밖에서 접근 가능한것, 대표적으로 지역변수같은거)
2. GC Root에서 참조 참조 해서 도달 가능한 객체를 찾아봄 -> 그래프 형태기때문에 DFS/BFS같은걸로 도달 가능한지 체크 가능.
3. 도달 가능하지 않는 객체들은 주기적으로 JVM에서 sweep시켜버림.
GC는 아닌데 IOS개발에서 사용하고 있는 메모리 관리 기법인 RC
ARC : automatic reference count
레퍼런스 하고있는걸 카운팅해서 해제할지 말지 결정하는거임.
클래스의 새로운 인스턴스를 만들때마다 메모리에 그 인스턴스들의 정보를 할당함.
instance를 만들면, heap 영역의 에 instance mapping table에 객체 주소값, RC 등을 추가함. // new Person();
스택영역의 local variable에다가 주소값 넣어줌 입혀줌. // let a = new Person();
그리고 RC++; 함.
해제되거나, 사용하지 않으면 메모리에서 지워주고 reference count 는 -1이됨.
<<예제>>
ref = new A();
ref2 = ref; // 강한참조
ref3 = ref; // 강한참조
현재 refcount = 3;
ref2 = null; // refcount = 2
ref3 = nul; // refcount = 1
현재 refcount = 1;
아직 살아있음.
ref = null
refcount = -1 => deinit이 불림.
+) RC와 GC의 비교
GC :
- 런타임에서 돌면서 인스턴스 체크,
- 그래서 인스턴스 해제 잘 되고, 신경쓸거 많이없음.
- 대신에 추가 리소스 필요. 그리고 개발자가 언제 해제될지 알 수 없음.
RC :
- 컴파일 타임에서 돌면서 인스턴스 체크.
- 컴파일 시에 메모리 해제 시점이 결정되니, 개발자가 직접 RC 카운팅 해보면 언제 해제되는지 알 수 있음.
- 추가 리소스 필요 없음.
- 대신 순환참조 신경써야함. 메모리에서 영원히 해제 안될 수 있음.
++) 강한참조문제
RC 마찬가지로 서로 강한참조로 물고있으면 영원히 해제 안됨.
그래서 Swift는 ref count 안늘리는 weak라는 약한참조를 명시할 수 있는것을 제공함.
let a = new Ref();
let b = new Ref();
a.you = b;
b.you = a;
서로 2씩 가지고있으므로,
a = nil // 2- 1 = 1;
b = nil // 2 -1 = 1;
해도 둘다 메모리에 남아있음.
GC 방식이라도 쓸데없는 참조때문에 메모리 릭이 날 수 있음.
예를들어 ArrayList의 각 셀에다가 중구난방으로 생성해놓고 사용하지 않고 방치해놓으면
객체는 사용안하지만 도달도 가능해서 GC가 해제 안시켜버림.
4. Lock의 종류
4-1) 락 구현 : 세마포어
현재 lock 상태를 정수로 보관
<동작방식>
처음 상태는 1.
만약 누가 락을 걸었으면 상태 -1
누가 락을 풀면 상태 +1
만약 락을 걸었는데 상태가 음수면 sleep()
락을 풀때, 한명 깨움.
4-2) 데이터베이스의 락
데이터베이스는 레코드 데이터가 일관성, 무결성을 유지하도록 레코드락을 걸어버림
1. shared lock: 읽기잠금.
- 일관성, 무결성을 유지한 데이터를 "읽으려고" lock을 검
- 그래서 수정 허용안됨 (이 상태에서 exclusive lock 불가)
- 다른 shared lock은 허용됨. 어처피 수정하는게아니라 같은 데이터 읽는거라 상관 무.
2. exclusive lock: 쓰기잠금.
- 일관성, 무결성을 유지한 채로 데이터를 "수정하려고" Lock을 검.
- 다른 exclusive lock, shared lock 불가. 아무도 읽지도 못함. 아무도 쓰지도 못함.
4-2-2) 트랜젝션 락.
RDMBS에서 트랜젝션의 무결성과 일관성을 보장하기 위해서 사용하는 락의 방식.
3. pessimistic lock:
만약 바꾸면 exclusive lock을 걸어서 못읽게 막음.
트렌젝션 다 스탑하고 항상 최신값으로 정보를 받아옴.
4. optimistic lock:
리코드를 읽을 때마다 버전정보가 바뀐적 없는지 체크.
만약 버전정보가 바뀐적이 있다면,
누군가 바꿨다는 의미로 중간에 바꿨단 의미로 추측.
바꿔도 상관없다고 할지라도 새롭게 업데이트 된 레코드 데이터로 tx완료를 위해 다시 시작.
4-2-3) Optimistic vs. Pessimistic locking
optimistic :
- 큰 단위/ 복잡한 시스템에서 유리 (중간에 락걸어서 멈출필요 없음)
- 데이터베이스와 직접 연결 세션도 필요없음. 버전정보 의지. (3티어 아키텍쳐에 적합, 클라이언트 + 비즈니스로직 + 데이터베이스)
Pessimistic
- 데드락 신경써야함.
- 락을 관리해야하기때문에 db세션 연결/유지 필수. (2티어 구조에 적합, 클라이언트 + 데이터)
- 혹은 db커넥션에 상관없이 txid를 공유할 수 있어야함. (two-phase commit의 프로토콜의 원리이기도 함 ,txid가지고 롤백)
No sql이지만, Redis도 Optimistic lock으로 구현. (근데 정확히모름 동작원리 알려주실분 있으면 ㄱㅅ)
댓글 0