라이브러리 캐시
: (라이브러리 캐시 체인은) 캐시 버퍼 체인과 라이브러리 캐시 체인은 근본적으로 동일한 목적 제공
즉, 특정한 항목의 위치를 매우 빠르게 찾는 방안 제공
- Repl_main = 현재 사용중인 버퍼들의 집합
- Repl_aux = 디스크로부터 블록을 읽거나 CR복제본 생성하려고 할 때, 재사용할 수 있는 버퍼
- (Shared Pool) LRU 리스트,메모리 Free List과 Shared Pool 간의 유사성
- 버퍼 캐시는 working data set 으로 나눠지고,
Shared Pool 은 다수의 서브 힙(Sub Heap)으로 나뉠수 있음 - Work data set 은 x$kcbwds 구조의 한 로우로 정의 되고
각 서브 힙은x$kghlu 구조의 한 로우로 정의됌 - 버퍼 캐시는 Main 과 AUX 리스트로
Shared Pool 은 LRU 리스트와 Free 리스트로 나눠진다. - 버퍼 캐시(MAIN)는 LRU(Least recently used)리스트를 소유하고 있으며
새로운 항목을 추가 할 때 midpoint insertion 알고리즘 사용
Shared Pool도 LRU 리스트를 소유하고 있으면 새로운 항목의 입력 위치는
리스트 내의 reccrrent 와 transient 부분의 경계지점 - 버퍼 캐시는 keep, recycle, default 세 개의 영역
Shared Pool 은 11g 부터"지속기간" 에 따라 네 영역으로 나뉨
- (Shared Pool) LRU 리스트,메모리 Free List과 Shared Pool 간의 차이점
- 버퍼 캐시는 동일한 크기의 청크로 구성
Shared Pool은 서로 다른 크기의 청크로 구성
Shared Pool의 구조
- 여러 개의 그래뉼(granule)로 구성
- SGA가 충분히 크다면 Shared Pool은 서브-풀(Sub-Pool)로 나뉠수 있음
- 각 서브-풀을 서로 다른 크래뉼로구성됌
- 11g 에서는 각 서브-풀은 "지속시간"에 따라 네 개의"sub-sub-pool"로 나뉨
- oradebug dump heapdump 2; 명령어 수행 결과
- 11g 에서는 각 서브-풀은 "지속시간"에 따라 네 개의"sub-sub-pool"로 나뉨
Shared Pool(sub Pool이나 지속기간에 따라) 나누는 이유
- 초장기 하나의 프로세스가 하나의 서브-풀만 이용하는 부작용으로 인해
다른 서브 풀에 충분한 메모리가 존재하여도 ORA-4031: unable to allocate %n bytes of memory 발생 - ORA-4031 발생 최소화
- 예약풀(reserved pool): 큰 메모리 청크를 여유 공간 확인 후 바로 예약 공간으로
- 표준화(Standadization): 딕셔너리 캐시 데이터를 위한 메모리 청크 사이즈를 표준화 시도 ( 잘게 쪼개짐 방지 = Fragmentation 방지 )
- 지속기간(Duration) : 업무 성격에 따른 Shared Pool 나눔, 단편화를 유발할 가능성이 높은 업무를 분리할 가능성도 높아짐
Shared Pool 구조의 우수성
익스텐트 리스트
- 클래스가 free 인 청크는 shared pool 프리 리스트에 존재
- 클래스가 R-Free 인 청크는 Shared Pool 예약 프리 리스트에 존재
- 클래스가 R-Freeable청크는"Stoppers" 용도로 사용 R-free 와 인접한 다른 청크와 구별
- 클래스가 freeable 은 free 상태로 전환될수 있는 메모리
- 클래스가 recreate 는 free 상태로 전환될수 있는 메모리 단, Destory call 수행 필요
프리 리스트
- 다양한 크기의 메모리 청크가 존재
- 짧은 링크드 리스트 검색 위해서
- 적절한 청크 크기를 검색 하기 위해서
LRU 리스트(들)
Shared Pool 내에는 permanent, recreatable 및 freeable 청크가 존재 하지만
LRU 리스트(들)에 존재하는 것은 recreatable 청크 뿐이다.
리스트 하단부를 보면 recreatable 청크의 개수는 12,085 개이고, 이 중 3,921 개는 recurrent(rcr)이고 8,164 개는 transient(trn)라는 것을 알 수 있다.
Tansient 는 separator 앞부분에 위치, recurrent 는 separator 뒷 부분에 위치
새로운 항목이 LRU 리스트에 추가되면 Transient 리스트 헤드에 등록
해당 항목이 한번 이상 사용되면 recurrent 리스트의 헤드로 이동
결과적으로 자주 사용하지 않는 오브젝트들은 transient 리스트에 위치, 자주 사용하는 오브젝트들은 recurrent 리스트에 위치
Shared Pool 메모리 획득에 대한 시나리오
(시나리오1) 운이 좋은 경우
세션은 shared pool 래치를 획득한 후 버킷을 검색 하여 원하는 크기의 청크를 찾는다면,
해당 청크를 프리 리스트에서 분리한 후, transient 리스트 헤더에 등록 그리고 청크에 핀(pin)을 설정하고,
shared pool 패치 릴리즈 만일 적당한 크기의 프리 청크를 못 찾는다면,
더 큰 크기의 청크 검색 하여 필요한 만큼만 자르고 나머지를 프리 리스트에 등록
만일 해당 버킷에서 적절한 청크를 찾지 못한다면,적절한청크를 찾을 때까지 다음 버킷으로 이동하여 청크를 검색 반복
(시나리오2) 운이 없는 경우
적당한 프리 청크를 찾지 못한다면
LRU 리스트의 꼬리(tail)의 끝으로 이동한 후 몇 개의 청크를 리스트로부터 분리한 후 프리(free)상태로 표시
그리고 이들 청크를 적절한 프리 리스트에 등록, ( 만일 해당 청크가 기존의 프리청크에 인접한 경우라면, 프리 리스트에 등록하기 전에 병합(Coalesce) 수행 )
그런 후에, 적절한 프리청크를 찾기 위해 다시 프리 리스트 버킷을 검색
(시나리오4) 큰 청크 할당
_shared_pool_reserved_min_alloc 값(기본 설정 4,400bytes)보다 큰 청크 요청 경우
운이 좋은 경우와 동일하게 작동하고, 프리청크를 찾지 못한다면, 예약된 프리 리스트 검색 LRU 리스트에서 몇 개의 청크를 분리한 후 프리청크를 병합
ORA-4031
시나리오 2와 3에서 본 것과 같이 ORA-4031 에러는 프리 리스트에서 적절한 프리청크를 찾지 못하고,
LRU 리스트를 검색하여(오라클 노트에 따르면 5회까지 수행) 기존의 청크를 분리한 후에도 적절한 프리청크를 생성하지 못할 때 발생
예방 : bind 변수 사용, dbms_pool.keep(큰청크필요문장)