2012-03-12 1 views
2

나는 모든 객체의 배열을 나타내는 void* 배열을 포함하는 행렬 유형을 가지고 있습니다 (예 : 모든 C 정수, 모든 float, double, 다양한 구조체 또는 가능한 모든 배열). 루비 VALUE s).Ruby 확장의 VALUE * 배열에서 마킹을 수행하는 방법은 무엇입니까?

VALUE의 행렬을 만들려고 시도하기 전에는 메모리 할당 및 가비지 수집이 올바르게 작동하는 것 같습니다. - 그렇지 않으면 NULL이 마크 기능을 위해 Data_Wrap_Struct에 전달되는이 실제로 VALUE 매트릭스 있다면 그래서에만 표시 않습니다

void mark_dense_storage(void* s) { 
    size_t i; 
    DENSE_STORAGE* storage = (DENSE_STORAGE*)s; 
    if (storage && storage->dtype == RUBY_OBJECT) 
    for (i = 0; i < count_dense_storage_elements(s); ++i) 
     rb_gc_mark(*((VALUE*)(storage->elements + i*sizeof(VALUE))); 
} 

:

나는 정의 된 다음 마크 기능을 가지고있다.

그러나 일부 VALUE 행렬 함수 (see gist)을 테스트 할 때 segfault가 발생합니다.

C[i+j*ldc] = rb_funcall(C[i+j*ldc], nm_id_mult, 1, beta); // C[i+j*ldc] = C[i+j*ldc]*beta 

nm_id_multrb_intern("*")로 내 Init 기능에 정의 된 전역 :

특히, 내가 VALUE* 배열의 첫 번째 객체에 루비 메서드를 호출하려고 처음 세그 폴트 것으로 보인다.

가비지 수집 문제는 아니지만 GC는 Ruby에서 가장 이해할만한 부분입니다. 또한 segfault는 포스터가 GC에 부여하는 this trace과 거의 동일합니다.

그래서, 내 질문 : 그것은 GC의 경우

  1. , VALUE의 배열을 표시하는 적절한 방법은 무엇입니까?

  2. GC가 아닌 경우 어떻게 이런 유형의 오류를 진단해야합니까? 나는 그런 것을 본 적이 없다.

편집 :

이 당신이 액세스를 시도하기 전에 *(VALUE*)a = INT2FIX(0)을 할 수 있는지 확인하십시오, C.

에 즉

을 만들어 VALUE의 초기화 실패의 예임을 밝혀 a.

나는 여전히 질문이 적절하다고 생각합니다. StackOverflow 나 그 밖의 곳에서 클린 - 스윕 쓰레기 수거를위한 마킹에 대한 좋은 예를 찾을 수 없었습니다. 그러한 예제 나 설명을 제공 할 수 있다면이 질문에 대한 정답으로 표시 할 것입니다.

+1

어떤 Ruby 버전입니까? –

+0

루비 1.9.3p0 (2011-10-30 수정 33570)입니다. –

+0

먼저 Ruby 1.9.3-p125로 업그레이드하고 문제가 아직 있는지 확인하십시오. p0에 GC와 관련된 몇 가지 문제가있었습니다. –

답변

1

Ruby의 마크 앤 스위프 GC는 두 단계로 작동합니다.

첫 번째 단계는 라이브 개체를 표시합니다. 알려진 각 "라이브 객체"의 마킹 기능을 호출하여 재귀 적으로 작동합니다. 라이브 객체의 초기 세트는 알려진 각 Ruby 스레드 또는 등록 된 전역 객체의 C 스택을 스캔하여 생성됩니다 (C 함수는 "알려진 라이브"객체를 등록/등록 취소합니다).오브젝트 X의 마킹 기능은 X가 참조하는 각 오브젝트에 대해 rb_gc_mark를 호출해야합니다. 다시 말해서, 당신이하는 일은 당신이해야하는 일입니다.

그러나 나중에 알 수 있듯이 유효한 VALUE는 유효한 Ruby 개체가 아닙니다. 그러나 Qnil (즉, nil)로 초기화하면 루비가 더 많을 것이라고 생각합니다.