2012-05-03 19 views
8

Me he dado cuenta de que los objetos tienen sus identificaciones asignadas de manera contraintuitiva. Cuanto antes se crea un objeto, mayor es su ID de objeto. Hubiera pensado que se les hubiera asignado en orden ascendente, en lugar de al revés.¿Por qué Ruby tiende a asignar identificadores de objeto en orden descendente?

Por ejemplo:

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

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

¿Por qué están asignados de tal manera, y también por qué hay un paso de 20, más de 1 de cada código dirigido por el intérprete de Ruby, pero una mucho mayor diferencia entre el objeto ID para el código ejecutado por Ruby's Irb?

+1

'object_id' es sólo un número entero que identifica de forma única un objeto, cualquier orden particular que creas que estás viendo es puramente un artefacto de implementación. –

+0

@theTinMan Shaving yaks? No, estoy tratando de satisfacer una curiosidad. – Matty

Respuesta

14

handwaving lo largo de muchos detalles, rubí asigna un trozo de la pila para poner objetos en:

1 | 2 | 3 | 4 | 5 

Luego atraviesa en orden y los añade a una lista enlazada de objetos libres. Esto les hace estar en el orden inverso en la lista enlazada:

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 

Al asignar un rubí objeto utiliza el primer elemento de la lista enlazada:

object = freelist 
freelist = object.next_free 

Así que la lista libre ahora se ve así:

freelist → 4 → 3 → 2 → 1 → NULL 

y otros objetos asignados aparecerán en orden inverso en pequeñas asignaciones.

Cuando rubí tiene que asignar un nuevo trozo de pila para almacenar más objetos verá el object_id saltar arriba continuación, ejecute de nuevo.

2

El intérprete de Ruby es un programa C, es probable que esté buscando en las correspondientes direcciones de memoria de los objetos.

0

Acabo de ejecutar un registro de identificadores de objeto, y parecía que, aunque las cosas iban en orden, la recolección de basura parecía hacer que las cosas pasaran de vez en cuando. Vi saltos de 20 a 80, por lo que parece ser casi aleatorio Pero con la cantidad de objetos internos que mantiene Ruby, los pedidos de identificación de objeto no son nada de los que se pueda depender. También podría ser que Ruby comienza en la parte superior de la plataforma local de int o short para permitir una prueba fácil por correr fuera (if(current_id==0) { problem }). Por lo que he visto de nuestros diversos números, parece ser completamente diferente e indeterminable. Me parece (casi) que Ruby incluso podría estar usando el puntero al objeto, porque eso se garantiza único, y explicaría las enormes brechas (20 bytes) entre los objetos. Cuando miro el valor devuelto por object_id, y lo miro junto al tamaño del puntero nativo de mi sistema (Intel de 64 bits).

que acaba de ejecutar un programa en C++ en prueba de ese mismo sistema que imprimió un puntero a un int. El puntero (en decimal) era 140734848324996 y el Id. De objeto de Ruby era 70118105405380. Los números no tienen mucho en común, pero ambos están en el mismo rango y se parecen a punteros.

Por supuesto, si alguien podría excavar en la fuente de Ruby y descubrir, que sería la respuesta definitiva. Lo estoy intentando.

2

Por lo que vale la pena, se puede ver una progresión totalmente diferente en las distintas aplicaciones; todos asignan sus objetos de una manera diferente, con cubos de diferentes tamaños.

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 
Cuestiones relacionadas