Como deve marcar a ser realizado em matrizes de VALOR* em um Ruby de extensão?
-
12-12-2019 - |
Pergunta
Eu tenho um tipo de matriz que contém um void*
matriz, que representa uma matriz de objetos (que são todos de um tipo em uma dada matriz, por exemplo, todos C números inteiros, todos os floats, doubles, uma variedade de estruturas, ou, possivelmente, até mesmo todos os Rubi VALUE
s).
A alocação de memória e de coleta de lixo parece funcionar corretamente até que eu tento criar uma matriz de VALUE
s.
Eu tenho a seguinte função de marcação definido:
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)));
}
Então é só marcar se é realmente um VALUE
matriz — caso contrário, NULL
é passada para Data_Wrap_Struct
para a função de marcação.
Mas eu estou ficando um segfault quando eu testar alguns dos VALUE
matriz de funções (ver gist).
Especificamente, parece segfault a primeira vez que eu tentar chamar um método Ruby sobre o primeiro objeto no VALUE*
matriz:
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_mult
é um global definido em meu Init
função rb_intern("*")
.
É possível que este não é um problema de coleta de lixo, mas o GC é a parte do Ruby que eu entendo a menos — e a minha segfault também é quase idêntica à este rastreamento, que o cartaz atributos para o GC.
Então, minhas perguntas:
Se o GC, que é a forma adequada para marcar uma matriz de
VALUE
s?Se não é o GC, como faço para ir sobre a diagnosticar este tipo de erro?Eu nunca vi nada parecido.
EDITAR:
Acontece que este é um exemplo de falha ao inicializar VALUE
s criado em C.
Em outras palavras, certifique-se de que para fazer *(VALUE*)a = INT2FIX(0)
antes de tentar acessar a
.
Eu ainda acho que a questão é relevante.Eu ainda não conseguiu encontrar quaisquer realmente bons exemplos de marcação para limpar e varrer a coleta de lixo, no StackOverflow ou em outro lugar.Se você pode fornecer um exemplo e/ou explicação, eu vou marcar que como uma resposta correta para esta pergunta.
Solução
Ruby mark-and-sweep GC funciona em duas fases.
A primeira fase marcas de objetos vivos.Funciona recursivamente chamando a função de marcação de cada conhecida "objetos vivos".O conjunto inicial de objetos vivos é produzido pela análise do C pilha de cada conhecida Ruby thread ou de cada registado objetos globais (existe uma função C para registar/cancelar conhecidos "ao vivo" de objectos).A função de marcação de objeto X deve, em seguida, chamar rb_gc_mark para cada objectos que X se refere.Em outras palavras, o que você faz é exatamente o que você deve fazer.
No entanto, como você percebeu, mais tarde, não qualquer VALOR possível é válido Ruby objeto.No entanto, eu acredito que a inicializar com Qnil (i.e.nil) seria mais ruby-ish.