2012-05-03 8 views
8

Tôi nhận thấy rằng các đối tượng có ID được gán theo kiểu phản trực giác. Đối tượng trước đó được tạo, ID đối tượng càng lớn. Tôi đã nghĩ họ sẽ được chỉ định theo thứ tự tăng dần, chứ không phải là cách khác.Tại sao Ruby có xu hướng gán ID đối tượng theo thứ tự giảm dần?

Ví dụ:

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

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

Tại sao họ được gán theo cách như vậy và cũng có lý do tại sao lại có một bước là 20, chứ không phải là 1 trong mã chạy bởi trình phiên dịch Ruby, nhưng một sự khác biệt lớn hơn rất nhiều giữa đối tượng ID cho mã chạy bởi irb của Ruby?

+1

'object_id' chỉ là một số nguyên xác định duy nhất một đối tượng, bất kỳ thứ tự cụ thể nào mà bạn nghĩ rằng bạn đang nhìn thấy chỉ là một hiện vật thực hiện. –

+0

@theTinMan Cạo yaks? Không, tôi đang cố thỏa mãn sự tò mò. – Matty

Trả lời

14

Handwaving qua nhiều chi tiết, ruby ​​phân bổ một đoạn của heap để đưa các đối tượng trong:

1 | 2 | 3 | 4 | 5 

Sau đó đi qua họ trong trật tự và thêm chúng vào một danh sách liên kết của các đối tượng miễn phí. Điều này làm cho họ được theo thứ tự ngược trên danh sách liên kết:

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 

Khi phân bổ một ruby ​​đối tượng sử dụng mục đầu tiên trong danh sách liên kết:

object = freelist 
freelist = object.next_free 

Vì vậy, các freelist bây giờ trông giống như:

freelist → 4 → 3 → 2 → 1 → NULL 

và các đối tượng được phân bổ tiếp theo sẽ xuất hiện theo thứ tự ngược lại giữa các phân bổ nhỏ.

Khi ruby ​​cần phân bổ một đoạn mới của heap để lưu trữ nhiều đối tượng hơn, bạn sẽ thấy object_id nhảy lên rồi chạy xuống một lần nữa.

2

Trình thông dịch Ruby là chương trình C, có thể bạn đang xem địa chỉ bộ nhớ tương ứng của các đối tượng.

0

Tôi chỉ chạy nhật ký các id đối tượng và dường như mọi thứ diễn ra theo thứ tự, bộ sưu tập rác dường như làm mọi thứ theo cách khác. dường như gần như là ngẫu nhiên. Nhưng với số lượng các đối tượng bên trong mà Ruby duy trì, các lệnh id đối tượng không có gì phụ thuộc vào. Nó cũng có thể là Ruby bắt đầu ở trên cùng của nền tảng địa phương int hoặc short để cho phép kiểm tra dễ dàng để chạy ra ngoài (if(current_id==0) { problem }). Từ những gì tôi đã nhìn thấy từ các số khác nhau của chúng tôi, nó có vẻ là hoàn toàn khác nhau và không thể xác định. Nó (gần như) trông với tôi như Ruby thậm chí có thể sử dụng con trỏ tới đối tượng, bởi vì đó là bảo đảm duy nhất, và sẽ giải thích những khoảng trống lớn (20 byte) giữa các đối tượng. Khi tôi nhìn vào giá trị trả về bởi object_id, và nhìn vào nó bên cạnh kích thước con trỏ nguyên gốc của hệ thống của tôi (64 bit Intel).

Tôi vừa chạy chương trình thử nghiệm C++ trên cùng một hệ thống đã in ra con trỏ đến int. Con trỏ (theo số thập phân) là 140734848324996 và ID đối tượng Ruby là 70118105405380. Các con số không có nhiều điểm chung, nhưng chúng đều nằm trong cùng một phạm vi và trông giống như con trỏ.

Tất nhiên, nếu ai đó đào sâu vào nguồn Ruby và tìm ra, đó sẽ là câu trả lời rõ ràng. Tôi đang cô.

2

Đối với những gì đáng giá, bạn có thể thấy sự tiến triển hoàn toàn khác nhau trên các triển khai khác nhau; tất cả mọi người phân bổ các đối tượng của họ theo một cách khác, với các nhóm có kích thước khác nhau.

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