이는 C 및 C++용 보수적 가비지 수집기 버전 8.3.0(다음 릴리스 개발)입니다.
라이센스: MIT 스타일
다운로드 페이지 또는 BDWGC 사이트에서 최신/안정적인 버전을 찾을 수 있습니다.
또한 개발 저장소에서 최신 버그 수정 및 새로운 기능을 사용할 수 있습니다.
이는 범용 가비지 수집 저장 할당자로 사용하기 위한 것입니다. 사용된 알고리즘은 다음에 설명되어 있습니다.
Boehm, H. 및 M. Weiser, "비협조적인 환경의 가비지 수집", 소프트웨어 실습 및 경험, 1988년 9월, 807-820페이지.
Boehm, H., A. Demers 및 S. Shenker, "대부분 병렬 가비지 수집", 프로그래밍 언어 설계 및 구현에 관한 ACM SIGPLAN '91 회의 진행, SIGPLAN 공지 26, 6(1991년 6월), pp. 157- 164.
Boehm, H., "공간 효율적이고 보수적인 가비지 수집", 프로그래밍 언어 설계 및 구현에 관한 ACM SIGPLAN '91 컨퍼런스 진행, SIGPLAN 공지 28, 6(1993년 6월), pp. 197-206.
Boehm H., "가비지 수집기 캐시 누락 감소", 메모리 관리에 관한 2000년 국제 심포지엄 간행물.
수집기와 최적화 컴파일러 사이의 가능한 상호 작용은 다음에서 논의됩니다.
Boehm, H. 및 D. Chase, "GC 안전 C 컴파일을 위한 제안", The Journal of C Language Translation 4, 2(1992년 12월).
Boehm H., "간단한 GC 안전 컴파일", 프로그래밍 언어 설계 및 구현에 관한 ACM SIGPLAN '96 컨퍼런스 진행.
두 번째 참조에 설명된 콜렉터와 달리 이 콜렉터는 전체 콜렉션(기본값) 동안 mutator가 중지된 상태로 작동하거나 할당 중에 증분적으로 작동합니다. (후자는 더 적은 수의 시스템에서 지원됩니다.) 가장 일반적인 플랫폼에서는 스레드 지원 여부에 관계없이 구축될 수 있습니다. 일부 플랫폼에서는 다중 프로세서를 활용하여 가비지 수집 속도를 높일 수 있습니다.
컬렉터의 기초가 되는 많은 아이디어는 이전에 다른 사람들에 의해 탐구되었습니다. 특히 1980년대 초 Xerox PARC에서 개발된 일부 런타임 시스템은 가능한 포인터를 찾기 위해 스레드 스택을 보수적으로 스캔했습니다(참조: Paul Rovner, "On Adding Garbage Collection and Runtime Types to a Strongly-Typed Statically Checked, Concurrent Language") 제록스 PARC CSL 84-7). Doug McIlroy는 버전 8 UNIX(tm)의 일부인 더 단순하고 완전히 보수적인 수집기를 작성했지만 널리 사용되지는 않은 것으로 보입니다.
수집기를 사용하는 상당히 정교한 문자열 패키지 "코드"와 마찬가지로 수집기를 누출 감지기로 사용하기 위한 기본 도구가 포함되어 있습니다. (README.cords 및 H.-J. Boehm, R. Atkinson 및 M. Plass, "Ropes: An Alternative to Strings", Software Practice and Experience 25, 12(1995년 12월), pp. 1315-1330을 참조하십시오. Xerox Cedar의 "rope" 패키지나 SGI STL 또는 g++ 배포판의 "rope" 패키지와 매우 유사합니다.
추가 수집기 문서는 개요에서 찾을 수 있습니다.
수집기의 알려진 용도 중 일부는 GitHub 알려진 클라이언트 페이지에 나열되어 있습니다.
이것은 C의 malloc에 대한 플러그인 대체품으로 사용하기 위한 가비지 수집 저장 할당자입니다.
수집기에서는 포인터에 태그를 지정할 필요가 없으므로 액세스할 수 없는 모든 저장소가 회수되는지 확인하려고 시도하지 않습니다. 그러나 경험상 명시적 할당 해제를 사용하는 대부분의 C 프로그램보다 사용되지 않은 메모리를 회수하는 데 일반적으로 더 성공적입니다. 수동으로 발생한 누수와 달리 회수되지 않은 메모리 양은 일반적으로 제한되어 있습니다.
다음에서 "객체"는 아래 설명된 루틴에 의해 할당된 메모리 영역으로 정의됩니다.
수집할 의도가 없는 개체는 액세스 가능한 다른 개체나 레지스터, 스택, 데이터 또는 정적으로 할당된 bss 세그먼트에서 가리켜야 합니다. 스택이나 레지스터의 포인터는 객체 내부의 어느 곳이든 가리킬 수 있습니다. 콜렉터가 ALL_INTERIOR_POINTERS
정의된 상태로 컴파일되거나 GC_all_interior_pointers
기본값으로 설정된 경우 힙 포인터의 경우에도 마찬가지입니다.
ALL_INTERIOR_POINTERS
없이 컴파일하면 힙에서 객체의 시작 부분까지 포인터를 요구함으로써 실수로 가비지 객체를 유지하는 일을 줄일 수 있습니다. 그러나 이는 가능한 주소 공간의 작은 부분을 차지하는 대부분의 프로그램에서는 더 이상 중요한 문제가 아닌 것으로 보입니다.
포인터 인식 알고리즘을 수정하는 루틴이 많이 있습니다. GC_register_displacement
하면 ALL_INTERIOR_POINTERS
정의되지 않은 경우에도 특정 내부 포인터를 인식할 수 있습니다. GC_malloc_ignore_off_page
사용하면 대형 개체의 중간에 있는 일부 포인터를 무시할 수 있으므로 대형 개체를 실수로 보유할 가능성이 크게 줄어듭니다. 대부분의 경우 매우 큰 개체 할당으로 인해 수집기 경고가 표시되는 경우 ALL_INTERIOR_POINTERS
로 컴파일하고 GC_malloc_ignore_off_page
사용하는 것이 가장 좋습니다. 자세한 내용은 여기를 참조하세요.
경고 : 표준(시스템) malloc
에 의해 할당된 메모리 내부의 포인터는 가비지 수집기에서 볼 수 없습니다. 따라서 해당 영역에서만 가리키는 개체가 조기에 할당 해제될 수 있습니다. 따라서 표준 malloc
가비지 수집 가능한 메모리에 대한 포인터를 포함하지 않는 것이 보장되는 I/O 버퍼와 같은 메모리 영역에만 사용하는 것이 좋습니다. C 언어 자동, 정적 또는 레지스터 변수의 포인터가 올바르게 인식됩니다. ( GC_malloc_uncollectable
표준 malloc과 의미가 비슷하지만 수집기가 추적하는 개체를 할당한다는 점에 유의하세요.)
경고 : 수집기는 동적 라이브러리와 연결된 데이터 영역에서 포인터를 찾는 방법을 항상 아는 것은 아닙니다. 운영 체제에서 해당 데이터 영역을 찾는 방법을 알고 있다면 이 문제를 쉽게 해결할 수 있습니다( GC_add_roots
참조). SunOS, IRIX 5.X 및 6.X, HP/UX, Alpha OSF/1, Linux 및 Win32에서 이 작업을 수행하기 위한 코드가 포함되어 기본적으로 사용됩니다. (Windows 세부사항은 README.win32 및 README.win64를 참조하십시오.) 다른 시스템에서는 동적 라이브러리 데이터 영역의 포인터가 수집기에서 고려되지 않을 수 있습니다. 동적 라이브러리 데이터 영역을 검색하는 수집기에 의존하는 프로그램을 작성하는 경우 해당 영역이 수집기에 표시되도록 GC_is_visible
에 대한 호출을 하나 이상 포함하는 것이 좋습니다.
가비지 수집기는 공유된 읽기 전용 데이터에 대해 알릴 필요가 없습니다. 그러나 공유 라이브러리 메커니즘이 포인터를 포함할 수 있는 연속되지 않은 데이터 영역을 도입할 수 있는 경우 수집기에 이를 알려야 합니다.
대부분의 신호에 대한 신호 처리는 수집 중에 그리고 할당 프로세스의 중단 없는 부분 동안 지연될 수 있습니다. 표준 ANSI C malloc과 마찬가지로 기본적으로 다른 malloc 호출이 진행 중인 동안 신호 처리기에서 malloc(및 기타 GC 루틴)을 호출하는 것은 안전하지 않습니다.
스레드로부터 안전한 작업을 위해 할당자/수집기를 구성할 수도 있습니다. (완전한 신호 안전성도 달성할 수 있지만 일반적으로 허용되지 않는 malloc당 두 개의 시스템 호출 비용만 발생합니다.)
경고 : 수집기는 스레드 로컬 저장소(예: pthread_getspecific
으로 액세스되는 종류) 검색을 보장하지 않습니다. 그러나 수집기는 스레드 스택을 검색하므로 일반적으로 가장 좋은 솔루션은 스레드 로컬 저장소에 저장된 모든 포인터가 수명 기간 동안 스레드 스택에도 저장되도록 하는 것입니다. (이것은 틀림없이 오래된 버그이지만 아직 수정되지 않았습니다.)
컬렉터를 빌드하는 방법에는 여러 가지가 있습니다.
CMake(권장되는 방법입니다)
GNU autoconf/automake
지그(실험적)
MS nmake (직접)
Makefile.direct
수동 C 컴파일
libgc(libcord도 포함)를 빌드하고 cmake를 사용하여 테스트를 실행하는 가장 간단한 방법은 다음과 같습니다.
mkdir outcd 출력 cmake -Dbuild_tests=ON .. cmake --build .ctest
이는 라이브러리를 구축하는 가장 크로스 플랫폼 방식입니다. 자세한 내용은 README.cmake를 참조하세요.
컬렉터 소스 저장소에는 configure
및 유사한 자동 생성 파일이 포함되어 있지 않으므로 소스 저장소에서 autoconf 기반 컬렉터 빌드의 전체 절차는 다음과 같습니다.
./autogen.sh ./구성 확인하다
GNU 스타일 빌드 프로세스는 일반적인 대상과 옵션을 이해합니다. make install
libgc와 libcord를 설치합니다. 모든 구성 옵션을 보려면 ./configure --help
시도하십시오. 현재 이런 방식으로 모든 빌드 옵션 조합을 실행하는 것은 불가능합니다.
자세한 내용은 README.autoconf를 참조하세요.
zig를 사용하여 수집기를 구축하고 테스트하는 것은 가장 간단한 형태로 간단합니다.
지그 빌드 테스트
변수를 사용하여 빌드를 구성할 수 있습니다(예: zig build -Denable_redirect_malloc -Denable_threads=false
. Zig는 뛰어난 크로스 컴파일 기능을 제공하며 다음과 같이 구성할 수 있습니다.
zig 빌드 -Dtarget=riscv64-linux-musl
현재 zig 0.12의 nightly 버전이 필요하며 https://ziglang.org/download/에서 다운로드할 수 있습니다.
Windows에서는 Microsoft 빌드 도구가 설치되고 적절하게 구성되어 있다고 가정하면 nmake -f NT_MAKEFILE check
입력하여 nmake
직접 사용하여 라이브러리를 빌드하고 테스트를 실행할 수 있습니다. 그러나 권장되는 방법은 위에서 설명한 대로 cmake를 사용하는 것입니다.
자세한 내용은 README.win32를 참조하세요.
이전 스타일(클래식) makefile 기반 빌드 프로세스의 경우 make -f Makefile.direct check
입력하면 libgc, libcord가 자동으로 빌드된 다음 gctest
와 같은 여러 테스트가 실행됩니다. 이 테스트는 수집기 기능에 대한 다소 피상적인 테스트입니다. 실패는 코어 덤프 또는 수집기가 손상되었다는 메시지로 표시됩니다. gctest
합리적인 2023 빈티지 64비트 데스크톱에서 실행하는 데 수십 초가 걸릴 수 있습니다. 최대 약 30MB의 메모리를 사용할 수 있습니다.
Makefile.direct는 링크해야 하는 라이브러리 libgc.a를 생성합니다.
마지막으로, 대부분의 대상에서 다음과 같이 단일 컴파일러 호출을 통해 수집기를 직접 구축하고 테스트할 수 있습니다(샘플에는 멀티스레딩 지원이 부족함).
cc -I include -o gctest 테스트/gctest.c extra/gc.c && ./gctest
예를 들어, 이는 디버깅 목적으로 편리할 수 있습니다.
README.macros 파일에 나열된 매크로를 정의하여 빌드 중에 라이브러리를 보다 정확하게 구성할 수 있습니다.
라이브러리는 다음과 같이 명시적으로 비활성화하지 않는 한 기본적으로 스레드 지원이 활성화된 상태로(즉, 스레드 안전 작업을 위해) 구축됩니다.
-Denable_threads=false
옵션이 cmake
또는 zig build
에 전달되었습니다.
--disable-threads
옵션이 ./configure
에 전달되었습니다.
수집기는 기본 구성에서 자동으로 작동합니다. 문제가 발생하는 경우 일반적으로 GC_PRINT_STATS
또는 GC_PRINT_VERBOSE_STATS
환경 변수를 정의하여 변경할 수 있습니다. 그러면 각 컬렉션에 대한 몇 줄의 설명 출력이 생성됩니다. (주어진 통계는 몇 가지 특이한 점을 보여줍니다. 여러 가지 이유로 합산되지 않는 것 같습니다. 특히 조각화 손실이 가장 두드러집니다. 이는 아마도 응용 프로그램보다 고안된 프로그램 gctest
에 훨씬 더 중요할 것입니다.)
libatomic_ops
의 사용(복제)은 이제 컴파일러가 원자 내장 함수를 지원하는 경우 선택 사항입니다. 대부분의 현대 컴파일러는 그렇습니다. 주목할만한 예외는 MS 컴파일러(Visual Studio 2022 기준)입니다.
필요한 경우 대부분의 OS 배포판에는 libatomic_ops
패키지가 있습니다. 또는 https://github.com/ivmai/libatomic_ops 공간에서 다운로드하거나 복제할 수 있습니다.
수집기는 현재 플랫 32비트 또는 64비트 주소 공간을 사용하는 시스템에서 본질적으로 수정되지 않은 상태로 실행되도록 설계되었습니다. 여기에는 대다수의 워크스테이션과 x86(i386 이상) PC가 포함됩니다.
몇몇 경우(예: OS/2, Win32)에는 별도의 makefile이 제공됩니다. 여기에는 별도의 호스트별 docs/platforms/README.* 파일이 있습니다.
동적 라이브러리는 SunOS/Solaris(최근 Sun 3 릴리스에서는 지원되지 않음), Linux, FreeBSD, NetBSD, IRIX, HP/UX, Win32(win32s 아님) 및 DEC의 OSF/1에서만 완벽하게 지원됩니다. AXP 머신과 아마도 dyn_load.c 상단 근처에 나열된 몇 가지 다른 머신이 있을 것입니다. 다른 컴퓨터에서는 다음 중 하나를 수행하는 것이 좋습니다.
동적 라이브러리 지원을 추가하고 코드를 보내주세요.
라이브러리의 정적 버전을 사용하십시오.
표준 malloc을 사용하도록 동적 라이브러리를 준비하십시오. 라이브러리가 가비지 수집 개체에 대한 포인터를 저장하는 경우 이는 여전히 위험합니다. 그러나 거의 모든 표준 인터페이스는 스택 할당 객체에 대한 포인터를 올바르게 처리하기 때문에 이를 금지합니다. ( strtok
예외입니다. 사용하지 마세요.)
모든 경우에 우리는 포인터 정렬이 표준 C 컴파일러에 의해 시행되는 정렬과 일치한다고 가정합니다. 비표준 컴파일러를 사용하는 경우 include/private/gc_priv.h
에 정의된 정렬 매개변수를 조정해야 할 수도 있습니다. 포인터에 대한 정렬을 덜 적용하는 경우 압축된 레코드/구조체에서도 문제가 될 수 있습니다.
바이트 주소가 지정되지 않거나 32비트 또는 64비트 주소를 사용하지 않는 시스템으로의 포트에는 상당한 노력이 필요합니다. 일반 MSDOS나 win16으로의 포팅은 어렵습니다.
아직 언급되지 않은 시스템이나 비표준 컴파일러의 경우 여기에 몇 가지 포팅 제안 사항이 제공됩니다.
다음 루틴은 사용자가 직접 호출하기 위한 것입니다. 일반적으로 GC_malloc
만 필요하다는 점에 유의하세요. 수집기가 비표준 위치(예: 수집기가 아직 이해하지 못하는 컴퓨터의 동적 라이브러리 데이터 영역)에서 추적해야 하는 경우 GC_clear_roots
및 GC_add_roots
호출이 필요할 수 있습니다. 일부 컴퓨터에서는 GC_stackbottom
다음으로 설정하는 것이 바람직할 수 있습니다. 스택 베이스(하단)에 대한 좋은 근사치입니다.
클라이언트 코드에는 다음을 모두 정의하는 gc.h
와 기타 여러 항목이 포함될 수 있습니다.
GC_malloc(bytes)
- 주어진 크기의 객체를 할당합니다. malloc과 달리 객체는 사용자에게 반환되기 전에 지워집니다. GC_malloc
이것이 적절하다고 판단되면 가비지 수집기를 호출합니다. GC_malloc은 운영 체제에서 충분한 공간을 확보할 수 없는 경우 0을 반환할 수 있습니다. 이는 공간 부족으로 인해 발생할 가능성이 가장 높은 결과입니다. 다른 가능한 결과는 스택 공간 부족으로 인해 함수 호출이 실패하거나, 내부 데이터 구조를 유지할 수 없기 때문에 수집기가 다른 방식으로 실패하거나, 중요한 시스템 프로세스가 실패하여 시스템을 중단시키는 것입니다. 이러한 가능성의 대부분은 malloc 구현과 무관합니다.
GC_malloc_atomic(bytes)
- 포인터를 포함하지 않는 것이 보장되는 지정된 크기의 객체를 할당합니다. 반환된 개체가 지워지는 것은 보장되지 않습니다. (항상 GC_malloc
으로 대체될 수 있지만 수집 시간이 더 빨라집니다. 정적으로 할당되는 경우보다 큰 문자 배열 등 GC_malloc_atomic
으로 할당되면 수집기가 더 빠르게 실행될 것입니다.)
GC_realloc(object, new_bytes)
- 객체의 크기를 주어진 크기로 변경합니다. 새 개체에 대한 포인터를 반환합니다. 이 포인터는 이전 개체에 대한 포인터와 동일할 수도 있고 동일하지 않을 수도 있습니다. 새로운 객체는 이전 객체가 원자적이었던 경우에만 원자성으로 간주됩니다. 새 객체가 복합적이고 원래 객체보다 큰 경우 새로 추가된 바이트가 지워집니다. 이는 새 개체를 할당할 가능성이 매우 높습니다.
GC_free(object)
- GC_malloc
이나 GC_malloc_atomic
또는 친구들에 의해 반환된 객체를 명시적으로 할당 해제합니다. 꼭 필요한 것은 아니지만 성능이 중요한 경우 컬렉션을 최소화하는 데 사용할 수 있습니다. 매우 작은 개체(<= 8바이트)의 경우 성능이 저하될 수 있습니다.
GC_expand_hp(bytes)
- 힙 크기를 명시적으로 늘립니다. (가비지 수집이 충분한 메모리를 회수하지 못한 경우 일반적으로 자동으로 수행됩니다. GC_expand_hp
에 대한 명시적 호출은 프로그램 시작 시 불필요하게 빈번한 수집을 방지할 수 있습니다.)
GC_malloc_ignore_off_page(bytes)
- GC_malloc
과 동일하지만 클라이언트는 객체가 활성화된 동안 객체의 첫 번째 GC 힙 블록(구성에 따라 512 .. 4096 바이트 이상) 내의 어딘가에 대한 포인터를 유지하겠다고 약속합니다. (이 포인터는 일반적으로 컴파일러 최적화로 인한 간섭을 방지하기 위해 휘발성으로 선언되어야 합니다.) 이는 100KB 정도보다 클 가능성이 있는 항목을 할당하는 데 권장되는 방법입니다. ( GC_malloc
으로 인해 해당 객체를 회수하지 못할 수도 있습니다.)
GC_set_warn_proc(proc)
- 수집기에서 경고를 리디렉션하는 데 사용할 수 있습니다. 이러한 경고는 드물어야 하며 코드 개발 중에 무시되어서는 안 됩니다.
GC_enable_incremental()
- 세대별 및 증분 수집을 활성화합니다. 페이지 더티 정보에 대한 액세스를 제공하는 머신의 대규모 힙에 유용합니다. 일부 더티 비트 구현은 주소 오류를 포착하여 디버깅을 방해하고 시스템 호출에 대한 힙 인수에 제한을 둘 수 있습니다(시스템 호출 내부의 쓰기 오류가 제대로 처리되지 않을 수 있으므로).
GC_register_finalizer(object, proc, data, 0, 0)
및 친구 - 종료 코드 등록을 허용합니다. 사용자가 제공한 종료 코드( (*proc)(object, data)
)는 객체에 연결할 수 없게 된 후 호출됩니다. 보다 정교한 사용 및 마무리 순서 문제에 대해서는 gc.h
참조하세요.
전역 변수 GC_free_space_divisor
더 적은 공간과 더 많은 수집 시간을 사용하기 위해 기본값인 3에서 위로 조정되거나 반대 효과를 위해 아래로 조정될 수 있습니다. 1로 설정하면 컬렉션이 거의 비활성화되고 모든 할당이 단순히 힙을 늘리게 됩니다.
일반적으로 0인 변수 GC_non_gc_bytes
는 수집 후보로 간주되어서는 안 되는 위 루틴에 의해 할당된 메모리 양을 반영하도록 변경될 수 있습니다. 물론 부주의하게 사용하면 과도한 메모리 소비가 발생할 수 있습니다.
include/private/gc_priv.h
상단 근처에 정의된 매개변수를 통해 일부 추가 조정이 가능합니다.
GC_malloc
만 사용하려는 경우 다음을 정의하는 것이 적절할 수 있습니다.
#define malloc(n) GC_malloc(n) #define calloc(m,n) GC_malloc((m)*(n))
매우 할당 집약적인 코드의 작은 조각에 대해 gc_inline.h
GC_malloc
및 그 친구 대신 사용할 수 있는 일부 할당 매크로가 포함되어 있습니다.
가비지 수집기에서 외부에 표시되는 모든 이름은 GC_
로 시작합니다. 이름 충돌을 피하기 위해 클라이언트 코드는 가비지 수집기 루틴에 액세스할 때를 제외하고 이 접두사를 피해야 합니다.
명시적인 유형 정보를 사용하여 할당하는 규정이 있습니다. 이는 거의 필요하지 않습니다. 자세한 내용은 gc_typed.h
에서 확인할 수 있습니다.
수집기에 대한 Ellis-Hull C++ 인터페이스는 수집기 배포에 포함됩니다. 이를 사용하려면 사용하는 빌드 시스템에 따라 ./configure --enable-cplusplus && make
(또는 cmake -Denable_cplusplus=ON . && cmake --build .
또는 make -f Makefile.direct c++
)를 입력하세요. 그러면 libgccpp.a 및 libgctba.a 파일이나 해당 공유 라이브러리 파일(libgccpp.so 및 libgctba.so)이 생성됩니다. 첫 번째(gccpp) 또는 두 번째(gctba) 중 하나와 연결해야 하지만 둘 다 연결할 수는 없습니다. 인터페이스 정의는 gc_cpp.h
및 여기를 참조하세요. 이 인터페이스는 컴파일러 변경 없이 Ellis-Detlefs C++ 가비지 수집 제안에 근접하려고 시도합니다.
STL 데이터 구조를 구성하려면 gc_allocator.h
와 여기에 선언된 할당자를 사용해야 하는 경우가 매우 많습니다. 그렇지 않으면 STL 데이터 구조의 하위 개체가 시스템 할당자를 사용하여 할당되며 참조하는 개체가 조기에 수집될 수 있습니다.
컬렉터는 malloc/free로 실행되도록 의도된 C 프로그램(예: 극도의 실시간 또는 이식성 제약이 있는 코드)에서 누출을 추적하는 데 사용될 수 있습니다. 그렇게 하려면 Makefile에서 FIND_LEAK
정의하세요. 이렇게 하면 명시적으로 해제되지 않은 액세스할 수 없는 개체가 발견될 때마다 수집기가 사람이 읽을 수 있는 개체 설명을 인쇄하게 됩니다. 이러한 개체도 자동으로 회수됩니다.
모든 개체가 GC_DEBUG_MALLOC
(다음 섹션 참조)로 할당된 경우 기본적으로 사람이 읽을 수 있는 개체 설명에는 최소한 소스 파일과 유출된 개체가 할당된 줄 번호가 포함됩니다. 때로는 이것으로 충분할 수도 있습니다. (일부 시스템에서는 암호 스택 추적도 보고합니다. 이것이 기호가 아닌 경우 tools/callprocs.sh foo
로 "foo" 프로그램을 호출하여 기호 스택 추적으로 호출될 수도 있습니다. 이는 짧은 쉘입니다. 프로그램 카운터 값을 기호 주소로 확장하기 위해 adb를 호출하는 스크립트는 주로 Scott Schwartz가 제공했습니다.
다음 섹션에서 설명하는 디버깅 기능은 누수 찾기 모드에서 약간 덜 효과적일 수 있습니다. 후자의 경우 GC_debug_free
실제로 개체를 재사용하기 때문입니다. (그렇지 않으면 개체가 단순히 유효하지 않은 것으로 표시됩니다.) 또한 대부분의 GC 테스트는 FIND_LEAK
모드에서 의미 있게 실행되도록 설계되지 않았습니다.
GC_debug_malloc
, GC_debug_malloc_atomic
, GC_debug_realloc
및 GC_debug_free
루틴은 메모리 덮어쓰기 오류 등에 대한 도움을 제공하는 수집기에 대한 대체 인터페이스를 제공합니다. 이러한 방식으로 할당된 개체에는 추가 정보가 주석으로 추가됩니다. 이 정보 중 일부는 가비지 수집 중에 확인되며, 발견된 불일치는 stderr에 보고됩니다.
할당된 개체의 끝을 지나서 쓰는 간단한 경우는 개체가 명시적으로 할당 해제되거나 개체가 활성화된 동안 수집기가 호출되는 경우 포착되어야 합니다. 개체의 첫 번째 할당 해제는 개체와 관련된 디버깅 정보를 지우므로 실수로 GC_debug_free
에 대한 반복 호출은 디버깅 정보 없이 개체의 할당 해제를 보고합니다. NULL
반환하는 것 외에도 메모리 부족 오류가 stderr에 보고됩니다.
가비지 수집 중 GC_debug_malloc
검사는 이 함수에 대한 첫 번째 호출로 활성화됩니다. 이로 인해 수집 중에 약간의 속도 저하가 발생합니다. 빈번한 힙 검사가 필요한 경우 디버거 등에서 GC_gcollect
명시적으로 호출하여 이를 수행할 수 있습니다.
GC_debug_malloc
할당 개체는 GC_realloc
또는 GC_free
로 전달되어서는 안 되며, 그 반대도 마찬가지입니다. 그러나 두 풀이 별개로 유지된다면 GC_debug_malloc
사용하여 일부 객체만 할당하고 다른 객체에 GC_malloc
사용하는 것은 허용됩니다. 이 경우 GC_malloc
할당 개체가 덮어쓴 것으로 잘못 식별될 가능성은 매우 낮습니다. 이는 최대 2**32분의 1의 확률로 발생해야 합니다. GC_debug_malloc
이 호출되지 않으면 이 확률은 0입니다.
GC_debug_malloc
, GC_debug_malloc_atomic
및 GC_debug_realloc
문자열과 정수라는 두 개의 추가 후행 인수를 사용합니다. 이는 할당자에 의해 해석되지 않습니다. 이는 객체에 저장됩니다(문자열은 복사되지 않음). 개체와 관련된 오류가 감지되면 인쇄됩니다.
매크로 GC_MALLOC
, GC_MALLOC_ATOMIC
, GC_REALLOC
, GC_FREE
, GC_REGISTER_FINALIZER
및 친구들도 제공됩니다. 여기에는 해당(비디버깅) 루틴과 동일한 인수가 필요합니다. gc.h
정의된 GC_DEBUG
에 포함된 경우 해당 함수의 디버깅 버전을 호출하여 적절한 경우 현재 파일 이름과 줄 번호를 두 개의 추가 인수로 전달합니다. GC_DEBUG
가 정의되지 않은 상태에서 gc.h
포함된 경우 이러한 모든 매크로는 대신 디버깅되지 않는 해당 항목으로 정의됩니다. ( 디버깅 정보가 있는 개체에 대한 포인터는 실제로 개체 시작에서 16바이트의 변위를 가리키는 포인터이므로 GC_REGISTER_FINALIZER
가 필요하며 마무리 루틴이 호출될 때 일부 변환이 필요합니다. 헤더에 저장되는 내용에 대한 자세한 내용은 정의를 참조하세요. dbg_mlc.c 파일의 oh 유형입니다.)
수집기는 일반적으로 가비지 수집 표시 단계 동안 클라이언트 코드를 중단합니다. 힙이 큰 프로그램에 대화형 응답이 필요한 경우 이는 허용되지 않을 수 있습니다. 수집기는 일반적으로 마지막 가비지 수집 이후 할당된 개체만 수집하려고 시도하는 "세대별" 모드에서 실행될 수도 있습니다. 또한 이 모드에서는 가비지 수집이 대부분 증분식으로 실행되며, 다수의 GC_malloc
요청 각각에 대한 응답으로 소량의 작업이 수행됩니다.
이 모드는 GC_enable_incremental
호출하여 활성화됩니다.
증분 및 세대별 수집은 수집기가 최근에 수정된 개체나 페이지를 알 수 있는 방법이 있는 경우에만 일시 중지 시간을 줄이는 데 효과적입니다. 수집기는 두 가지 정보 소스를 사용합니다.
VM 시스템에서 제공하는 정보입니다. 이는 여러 형태 중 하나로 제공될 수 있습니다. Solaris 2.X(및 잠재적으로 다른 유사한 시스템)에서는 더티 페이지에 대한 정보를 /proc 파일 시스템에서 읽을 수 있습니다. 다른 시스템(예: SunOS4.X)에서는 힙을 쓰기 방지하고 결과적인 오류를 포착하는 것이 가능합니다. 이러한 시스템에서는 힙에 쓰는 시스템 호출(읽기 제외)을 클라이언트 코드에서 특별히 처리해야 합니다. 자세한 내용은 os_dep.c
참조하세요.
프로그래머가 제공한 정보입니다. 라이브러리가 적절하게 컴파일된 경우 GC_end_stubborn_change
를 호출한 후 객체는 더티로 간주됩니다. 일반적으로 수명이 짧은 객체에는 사용할 가치가 없습니다. GC_end_stubborn_change
또는 GC_reachable_here
호출 누락으로 인해 발생한 버그는 매우 드물게 관찰되고 추적하기 어려울 수 있습니다.
인식 가능한 포인터가 없는 메모리는 회수됩니다. 목록의 정방향 및 역방향 링크를 배타적으로 연결해도 잘리지 않습니다.
일부 C 최적화 프로그램은 영리한 최적화의 결과로 메모리 개체에 대한 위장되지 않은 마지막 포인터를 잃을 수 있습니다. 이것은 실제로 거의 관찰되지 않았습니다.
이것은 실시간 수집기가 아닙니다. 표준 구성에서 수집에 필요한 시간 비율은 힙 크기 전체에서 일정해야 합니다. 그러나 힙이 클수록 수집 일시 중지가 늘어납니다. 병렬 표시가 활성화된 경우 프로세서 수에 따라 감소합니다.
(2007년 빈티지 시스템에서 GC 시간은 스캔하고 처리해야 하는 액세스 가능한 메모리 MB당 5ms 정도일 수 있습니다. 마일리지는 다를 수 있습니다.) 경우에 따라 증분/세대별 수집 기능이 도움이 될 수 있습니다.
GitHub 문제에 대한 버그 보고서와 새로운 기능 아이디어를 해결해 주세요. 제출하기 전에 다른 사람이 아직 제출하지 않았는지 확인하십시오.
기여하고 싶다면 GitHub에 풀 요청을 제출하세요. 제출 전 수정된 파일을 clang-format으로 처리하시기 바랍니다.
도움이 필요하면 Stack Overflow를 사용하세요. 이전 기술 토론은 bdwgc
메일링 목록 아카이브에서 확인할 수 있습니다. 압축 파일로 다운로드하거나 Narkive에서 찾아볼 수 있습니다.
새로운 출시 소식을 받으려면 RSS 피드를 구독하세요. (이메일로 알림을 받으려면 IFTTT RSS 피드와 같은 타사 무료 서비스를 설정할 수 있습니다.) 모든 문제에 대한 알림을 받으려면 GitHub에서 프로젝트를 시청하세요.
우리의 의도는 무료 소프트웨어와 독점 소프트웨어 모두에서 bdwgc(libgc)를 쉽게 사용할 수 있도록 하는 것입니다. 따라서 클라이언트 애플리케이션에 동적으로 또는 정적으로 연결될 것으로 예상되는 Boehm-Demers-Weiser 보수적 가비지 수집기 코드는 자체 라이센스로 보호되며 이는 MIT 스타일의 라이센스와 유사합니다.
정확한 라이센스 정보는 LICENSE 파일에 제공됩니다.
모든 기여자는 AUTHORS 파일에 나열됩니다.