sicp.io
5.3.2 · 무한 메모리의 환상 유지하기

살아 있는 셀을 복사하고 되풀이된 참조는 전달하며 쓰레기는 남겨 둔다.

명시적인 root 집합에서 닿는 그래프만 새 벡터 메모리로 옮기고 재귀 복사 전에 forwarding 포인터를 설치하여 공유 꼬리와 순환을 모두 보존합니다.

생각해 볼 질문

공유 객체를 복제하거나 순환을 끝없이 도는 일 없이 살아 있는 저장 공간을 어떻게 압축할까요?

  • from-space와 비어 있는 to-space 구분하기
  • root에서 닿는 순서쌍 포인터만 복사하기
  • 필드를 재귀 복사하기 전에 forwarding 항목 설치하기
  • 같은 옛 셀의 모든 참조에 새 포인터 하나 재사용하기
  • forwarding된 포인터로 순환 보존하기
  • 회수된 셀 수와 free 포인터의 변화 재기

copy-value는 원자를 그대로 돌려줍니다. 순서쌍 포인터는 먼저 옛 인덱스의 forwarding 항목을 확인합니다. 항목이 없으면 to-space에 placeholder 셀을 하나 할당하고 두 필드를 따라가기 전에 새 포인터를 기록합니다. 그 뒤 car와 cdr를 재귀 복사해 placeholder에 넣습니다. 먼저 기록하는 순서가 공유와 순환을 모두 유한하게 만듭니다.

첫 힙에는 셀 다섯 개가 있지만 root 두 개에서 닿는 셀은 세 개뿐입니다. 복사된 left와 right는 복사된 shared 꼬리 하나를 가리키고 쓰레기 셀 두 개의 forwarding 항목은 #f로 남습니다. 두 번째 힙의 자기 순환은 cdr 복사가 옛 포인터를 다시 만났을 때 이미 기록된 새 포인터를 즉시 재사용합니다.

SICP 코드UTF-8 4,742 / 1,048,576바이트
예제
결과
출력
진단
실행 추적0 / 0 개 이벤트
    실행은 브라우저 안에서 이루어지며 프로그램 결과와 실행 추적을 보여줍니다.
    예상 결과

    공유 그래프 수집은 (5 3 2 (a shared) (b shared) #t #f #f)를 반환합니다. 순환 수집은 (1 node #t #f)를 반환합니다.

    실행 추적에서 볼 점

    공유 그래프에서는 옛 shared 포인터의 첫 등장이 새 할당으로 가고 두 번째 등장은 기존 forwarding 항목으로 가는지 보세요. 옛 인덱스 3과 4는 방문하지 않습니다. 순환에서는 cdr 복사가 옛 node에 다시 닿기 전에 forwarding 쓰기가 일어나는지 확인하세요.

    직접 해보기

    프로그램을 수정하고 결과를 비교해 보세요.

    shared 꼬리를 직접 가리키는 세 번째 root를 추가하고 복사된 꼬리를 변경하세요. 새 할당 수와 모든 root 관찰을 예상한 뒤 semispace를 바꾸고 셀 하나를 더 할당하세요.

    힌트 보기

    이미 forwarding된 객체를 가리키는 root는 복사 셀 수를 늘리지 않습니다. 수집 뒤 클라이언트는 낡은 from-space 포인터가 아니라 다시 쓴 root를 사용해야 합니다.

    이 수업 완료하기

    이 장의 총 23개 수업 중 0개 완료0%