2012-05-03 14 views
8

Zauważyłem, że obiekty mają przypisane ich identyfikatory w sposób sprzeczny z intuicją. Im wcześniej obiekt zostanie utworzony, tym większy będzie jego identyfikator obiektu. Sądziłem, że zostałyby przydzielone w porządku rosnącym, a nie na odwrót.Dlaczego Ruby ma tendencję do przypisywania identyfikatorów obiektów w porządku malejącym?

Na przykład:

obj1 = Object.new 
obj2 = Object.new 
obj3 = Object.new 

p obj1.object_id # => 4806560 
p obj2.object_id # => 4806540 
p obj3.object_id # => 4806520 

Dlaczego są one przypisane w taki sposób, a także dlaczego jest to krok 20 zamiast 1 w kodzie prowadzony przez interpreter Ruby, ale znacznie większą różnicę między obiektem Identyfikatory dla kodu uruchomionego przez irbę Ruby?

+1

'object_id' jest tylko liczbą całkowitą, która jednoznacznie identyfikuje obiekt, każda kolejność, którą uważasz, że widzisz, jest wyłącznie artefaktem implementacji. –

+0

@TinMan golenie jaków? Nie, staram się zaspokoić ciekawość. – Matty

Odpowiedz

14

Handwaving nad wieloma szczegółami, rubin przydziela kawał hałdy umieścić obiekty w:

1 | 2 | 3 | 4 | 5 

Następnie przemierza nich zamówienie i dodaje je do połączonego liście wolnych obiektów. Powoduje to, że im się w odwrotnej kolejności na linkowane listy:

freelist → NULL 
freelist → 1 → NULL 
freelist → 2 → 1 → NULL 
freelist → 3 → 2 → 1 → NULL 
freelist → 4 → 3 → 2 → 1 → NULL 
freelist → 5 → 4 → 3 → 2 → 1 → NULL 

Kiedy przypisania rubin obiektu używa pierwszego elementu na połączonej listy:

object = freelist 
freelist = object.next_free 

Więc freelist teraz wygląda następująco:

i kolejne przydzielone obiekty będą wyświetlane w odwrotnej kolejności dla małych alokacji.

Kiedy ruby ​​musi przydzielić nowy kawałek sterty, aby przechowywać więcej obiektów, zobaczysz, że id_obiektu się podniósł, a następnie ponownie spłynął.

2

Interpreter Ruby to program w języku C, prawdopodobnie patrzysz na odpowiadające adresy pamięci obiektów.

0

prostu prowadził dziennik identyfikatorów obiektów, i wydawało się, że mimo wszystko poszło w porządku, zbieranie śmieci wydawało się dokonać rzeczy iść w drugą stronę co jakiś while.I zobaczył jak skacze z 20 do 80, więc wydaje się prawie przypadkowa. Ale z ilością wewnętrznych obiektów, które utrzymuje Ruby, nie ma na czym polegać porządek identyfikatora obiektu. Może się również zdarzyć, że Ruby zacznie działać u góry platformy lokalnej int lub short, aby umożliwić łatwy test na wyczerpanie (if(current_id==0) { problem }). Z tego, co widziałem z różnych liczb, wydaje się zupełnie inny i niemożliwy do określenia. To (prawie) wygląda na to, że Ruby może nawet używać wskaźnika do obiektu, ponieważ jest to gwarantowane unikatowe i wyjaśniałoby wielkie przerwy (20 bajtów) między obiektami. Kiedy patrzę na wartość zwróconą przez object_id, spójrz na to obok rozmiaru wskaźnika natywnego mojego systemu (64-bitowy Intel).

Właśnie uruchomiłem testowy program C++ na tym samym systemie, który wydrukował wskaźnik do int. Wskaźnik (w systemie dziesiętnym) to 140734848324996, a identyfikator obiektu Ruby to 70118105405380. Liczby nie mają wiele wspólnego, ale oba są w tym samym zakresie i wyglądają jak wskaźniki.

Oczywiście, jeśli ktoś mógłby zagłębić się w źródło Ruby i dowiedzieć się, to byłaby ostateczna odpowiedź. Próbuję.

2

Dla tego, co jest warte, można zobaczyć zupełnie inny postęp w różnych implementacjach; wszyscy przydzielają swoje obiekty w inny sposób, za pomocą wiader o różnych rozmiarach.

MRI 1.9.3

objs = [Object.new, Object.new, Object.new] 
objs.each {|o| puts o.object_id} 
# 70257700803740 
# 70257700803700 
# 70257700803680 

jruby

objs = [Object.new, Object.new, Object.new] 
objs.each {|o| puts o.object_id} 
# 2048 
# 2050 
# 2052 

RBX

objs = [Object.new, Object.new, Object.new] 
objs.each {|o| puts o.object_id} 
# 3920 
# 3924 
# 3928 
Powiązane problemy