Wie sollte die Markierung für Arrays von VALUE* in einer Ruby-Erweiterung erfolgen?
-
12-12-2019 - |
Frage
Ich habe einen Matrixtyp, der a enthält void*
Array, das ein Array von Objekten darstellt (die alle von einem Typ in einer bestimmten Matrix sind, z. B. alle C-Ganzzahlen, alle Floats, Doubles, eine Vielzahl von Strukturen oder möglicherweise sogar alle Ruby). VALUE
S).
Speicherzuweisung und Speicherbereinigung scheinen ordnungsgemäß zu funktionieren, bis ich versuche, eine Matrix zu erstellen VALUE
S.
Ich habe die folgende Markierungsfunktion definiert:
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)));
}
Es erfolgt also nur eine Markierung, wenn es sich tatsächlich um eine handelt VALUE
Matrix – andernfalls NULL
wird weitergeleitet an Data_Wrap_Struct
für die Markierungsfunktion.
Aber ich erhalte einen Segfault, wenn ich einige davon teste VALUE
Matrixfunktionen (siehe Kern).
Insbesondere scheint es beim ersten Versuch, eine Ruby-Methode für das allererste Objekt in aufzurufen, zu einem Segfault zu kommen VALUE*
Array:
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
ist eine globale Definition in meinem Init
funktionieren als rb_intern("*")
.
Es ist möglich, dass es sich hierbei nicht um ein Garbage-Collection-Problem handelt, aber der GC ist der Teil von Ruby, den ich am wenigsten verstehe – und mein Segfault ist auch fast identisch damit diese Spur, was der Poster dem GC zuschreibt.
Also meine Fragen:
Wenn es sich um den GC handelt, wie markiert man dann ein Array von?
VALUE
S?Wenn es nicht der GC ist, wie kann ich diesen Fehlertyp diagnostizieren?So etwas habe ich noch nie gesehen.
BEARBEITEN:
Es stellt sich heraus, dass dies ein Beispiel für einen Fehler bei der Initialisierung ist VALUE
wurde in C erstellt.
Mit anderen Worten: Stellen Sie sicher, dass Sie dies tun *(VALUE*)a = INT2FIX(0)
bevor Sie versuchen, darauf zuzugreifen a
.
Ich halte die Frage immer noch für relevant.Ich habe es nicht geschafft, wirklich gute Beispiele für die Markierung für die Clean-and-Sweep-Garbage Collection zu finden, weder auf StackOverflow noch anderswo.Wenn Sie ein solches Beispiel und/oder eine solche Erklärung liefern können, markiere ich dies als richtige Antwort auf diese Frage.
Lösung
Rubys Mark-and-Sweep-GC arbeitet in zwei Stufen.
Die erste Stufe markiert lebende Objekte.Es funktioniert rekursiv, indem es die Markierungsfunktion jedes bekannten „lebenden Objekts“ aufruft.Der anfängliche Satz an Live-Objekten wird durch Scannen des C-Stacks jedes bekannten Ruby-Threads oder jedes registrierten globalen Objekts erstellt (es gibt eine C-Funktion zum Registrieren/Abmelden von „bekannten Live“-Objekten).Die Markierungsfunktion von Objekt X sollte dann rb_gc_mark für jedes Objekt aufrufen, auf das X verweist.Mit anderen Worten: Was Sie tun, ist genau das, was Sie tun sollten.
Allerdings ist, wie Sie später bemerkt haben, nicht jeder mögliche VALUE ein gültiges Ruby-Objekt.Ich glaube jedoch, dass die Initialisierung mit Qnil (d. h.Null) wäre eher rubinrot.