2009-06-30 34 views
62

Thông thường việc triển khai mặc định là Object.hashCode() là một số chức năng của địa chỉ được phân bổ của đối tượng trong bộ nhớ (mặc dù điều này không được bắt buộc bởi JLS). Cho rằng VM shunts đối tượng về trong bộ nhớ, tại sao giá trị trả lại bởi System.identityHashCode() không bao giờ thay đổi trong suốt thời gian của đối tượng?Làm thế nào để JVM đảm bảo rằng System.identityHashCode() sẽ không bao giờ thay đổi?

Nếu đó là phép tính "một lần" (đối tượng hashCode được tính một lần và xếp vào tiêu đề đối tượng hoặc thứ gì đó), thì điều đó có nghĩa là có thể có hai đối tượng có cùng số identityHashCode (nếu chúng xảy ra để được phân bổ đầu tiên tại cùng một địa chỉ trong bộ nhớ)?

+1

Câu hỏi liên quan: Địa chỉ bộ nhớ đó có phải là địa chỉ bộ nhớ thực hoặc thứ gì đó ảo có thể giữ cố định ngay cả khi đối tượng bị xáo trộn không?Nếu ảo, điều đó sẽ tốt đẹp vì các con trỏ tới nó sẽ không cần phải được điều chỉnh. Mặt khác, điều này có nghĩa là một sự thêm vào và một bảng ánh xạ có khả năng lớn. – Thilo

+3

Đó là một sự sắp xếp lại nhẹ của địa chỉ khi được yêu cầu lần đầu. (Trả về một mã băm với các bit thấp tất cả các số không là không lớn.) –

+0

Thực ra, nó nói rằng identityHashCode không bao giờ phải thay đổi? JavaDoc cho System.identityHashCode không rõ ràng về điều đó. – Thilo

Trả lời

35

Các JVM hiện đại lưu giá trị trong tiêu đề đối tượng. Tôi tin rằng giá trị thường được tính chỉ khi sử dụng lần đầu tiên để giữ thời gian dành cho phân bổ đối tượng ở mức tối thiểu (đôi khi xuống tới mức thấp nhất là một chục chu kỳ). Sun JVM chung có thể được biên dịch sao cho mã băm nhận dạng luôn luôn là 1 cho tất cả các đối tượng.

Nhiều đối tượng có thể có cùng mã băm nhận dạng. Đó là bản chất của mã băm.

+3

Right - Tôi vừa xem xét ObjectSynchronizer :: FastHashCode trong Synchronizer.cpp (mã nguồn thời gian chạy vm) và sau khi tạo hashcode, có vẻ như nó kết hợp nó vào phần đầu của đối tượng. Có vẻ như có một số triển khai có thể có của HashCode; một trong những bạn allude để trả về 1 cho tất cả các đối tượng được sử dụng để đảm bảo không có một phần của VM giả định hashcodes là duy nhất vì lý do nào. – butterchicken

+0

public static native int identityHashCode (Object x); là một phương thức gốc. Bạn có thể giải thích nó từ quan điểm mã được triển khai gốc không? Tôi có nghĩa là thực hiện C++.it chủ yếu được sử dụng trong inIdentityHashMap phải không? –

+0

@Tom Bạn có ý nghĩa gì bởi tiêu đề đối tượng? Bạn cũng đã viết "Tôi tin rằng giá trị thường được tính chỉ khi sử dụng lần đầu tiên để giữ cho phân bổ đối tượng ở mức tối thiểu (đôi khi xuống đến mức thấp nhất là một chục chu kỳ)." Bạn có thể giải thích phân bổ đối tượng nào bạn đang đề cập đến ở đây không? – Geek

-3

Theo như tôi biết, điều này được thực hiện để trả lại tham chiếu, điều đó sẽ không bao giờ thay đổi trong thời gian tồn tại của đối tượng.

+0

Vì vậy, bạn đang nói rằng tham chiếu không phải là một địa chỉ bộ nhớ thực (hoặc trực tiếp bắt nguồn từ đó). Vì vậy, nó là một loại của một con trỏ đến địa chỉ bộ nhớ thực? – Thilo

15

Trong câu trả lời cho câu hỏi thứ hai, bất chấp việc triển khai, có thể cho nhiều đối tượng có cùng một identityHashCode.

Xem bug 6321873 để có một cuộc thảo luận ngắn gọn về từ ngữ trong javadoc và một chương trình để chứng minh tính không độc đáo.

+1

Đúng. Hai đối tượng khác nhau có thể có cùng một hashCode. Đó là trường hợp với tất cả các hàm băm (trên một tên miền lớn hơn kích thước kết quả của chúng). – Thilo

+2

Đó là một báo cáo lỗi rất tốt mà. :) –

+1

@Thilo: JVM có thể đã được viết theo cách như vậy để đảm bảo rằng, với điều kiện không bao giờ có hơn bốn tỷ đối tượng tồn tại cùng một lúc, 'identityHashCode' sẽ không bao giờ trả về một giá trị đã được trả về cho bất kỳ đối tượng nào khác đối tượng vẫn còn tồn tại. Tùy thuộc vào cách trình quản lý bộ nhớ được triển khai, điều này có thể tốn kém hoặc có thể không thêm chi phí bổ sung. Ví dụ, một 'Object' có thể chứa một chỉ mục thành một bảng con trỏ, với mỗi đối tượng được gán một vị trí bảng bất biến miễn là nó tồn tại. Các triển khai JVM điển hình không làm điều đó ... – supercat

0

Các hướng dẫn chung cho việc thực hiện một chức năng băm là:

  • cùng một đối tượng phải trả lại một hashCode phù, nó không nên thay đổi theo thời gian hoặc phụ thuộc vào bất kỳ thông tin biến (ví dụ như một thuật toán hạt bởi một số ngẫu nhiên hoặc giá trị của các trường thành viên có thể thay đổi
  • hàm băm cần có một phân phối ngẫu nhiên tốt phân phối ngẫu nhiên tốt và ý tôi là nếu bạn xem mã băm dưới dạng nhóm, 2 đối tượng nên ánh xạ tới các nhóm khác nhau (mã băm) càng nhiều càng tốt Khả năng 2 đối tượng sẽ có cùng một hashcode nên hiếm - mặc dù nó có thể xảy ra.
0

Tiêu đề của đối tượng trong HotSpot bao gồm và con trỏ lớp và từ "đánh dấu".

Mã nguồn của cấu trúc dữ liệu cho từ đánh dấu có thể tìm thấy tệp markOop.hpp. Trong tập tin là một lời nhận xét mô tả cách bố trí bộ nhớ của từ dấu:

hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)

Ở đây chúng ta có thể thấy rằng các mã băm sắc cho Java bình thường các đối tượng trên một hệ thống 32 bit được lưu trong đánh dấu từ và nó dài 25 bit.

Các vấn đề liên quan