2012-02-29 52 views
10

Tôi tò mò muốn biết các tham chiếu đối tượng C# được biểu diễn như thế nào trong bộ nhớ trong thời gian chạy (trong .NET CLR). Một số câu hỏi mà bạn nghĩ đến là:các tham chiếu đối tượng C# được thể hiện như thế nào trong bộ nhớ/thời gian chạy (trong CLR)?

  1. Tham chiếu đối tượng chiếm bao nhiêu bộ nhớ? Nó có khác khi được định nghĩa trong phạm vi của một lớp so với phạm vi của một phương thức không? Có nơi nó sống khác nhau dựa trên phạm vi này (stack vs heap)?

  2. Dữ liệu thực tế được duy trì trong tham chiếu đối tượng là gì? Nó chỉ đơn giản là một địa chỉ bộ nhớ trỏ đến đối tượng mà nó đề cập hoặc có nhiều hơn không? Điều này có khác nhau dựa trên việc nó được xác định trong phạm vi của một lớp hay phương thức?

  3. Các câu hỏi tương tự như trên, nhưng lần này khi nói về tham chiếu đến tham chiếu, như khi tham chiếu đối tượng được chuyển đến phương thức theo tham chiếu. Câu trả lời cho 1 và 2 thay đổi như thế nào?

+3

Lưu ý rằng những câu hỏi này là tất cả các chi tiết triển khai (có thể thay đổi,) và không thực sự về C#, mà đúng hơn là về .NET CLR. – dlev

+0

Chopperdave, câu hỏi thú vị nhưng tôi muốn hỏi xem bạn có hỏi ý bạn không - Một tham chiếu đối tượng phần lớn là con trỏ và đó chỉ là 'số' tùy thuộc vào kiến ​​trúc của hệ thống mà mã của bạn đang chạy. Nếu bạn hỏi về cách phân bổ. Heap của Net hoạt động, đó là một con thú hoàn toàn khác. –

+0

Chỉ muốn thêm, không có xúc phạm dự định ở đây, tôi không cố gắng ngụ ý rằng bạn không biết ý bạn là gì - Điều này là, trong đó .Net đây là một câu hỏi mơ hồ và nó sẽ giúp người dùng trong tương lai trên Stack Tràn để biết chính xác bối cảnh mà chúng ta đang nói đến. –

Trả lời

12

Câu trả lời này dễ hiểu nhất nếu bạn hiểu các con trỏ C/C++. Một con trỏ chỉ đơn giản là địa chỉ bộ nhớ của một số dữ liệu.

  1. Tham chiếu đối tượng phải là kích thước của con trỏ, thường là 4 byte trên CPU 32 bit và 8 byte trên CPU 64 bit. Nó là như nhau bất kể nơi nó được xác định. Nơi nó sống phụ thuộc vào nơi nó được xác định. Nếu nó là một trường của một lớp, nó sẽ nằm trên heap trong đối tượng nó là một phần của. Nếu nó là một trường tĩnh, nó nằm trong một phần đặc biệt của đống mà không phải chịu thu gom rác thải. Nếu nó là một biến cục bộ, nó sẽ nằm trên ngăn xếp.

  2. Tham chiếu đối tượng chỉ đơn giản là một con trỏ, có thể được hiển thị dưới dạng int hoặc dài chứa địa chỉ của đối tượng trong bộ nhớ. Nó là như nhau bất kể nơi nó được xác định.

  3. Điều này được triển khai dưới dạng con trỏ trỏ đến con trỏ. Dữ liệu giống nhau - chỉ là một địa chỉ bộ nhớ. Tuy nhiên, không có đối tượng tại địa chỉ bộ nhớ đã cho. Thay vào đó, có một địa chỉ bộ nhớ khác, đó là tham chiếu ban đầu cho đối tượng. Đây là những gì cho phép một tham số tham chiếu được sửa đổi. Thông thường, một tham số biến mất khi phương thức của nó hoàn tất. Vì tham chiếu đến đối tượng không phải là tham số nên các thay đổi đối với tham chiếu này sẽ vẫn còn. Tham chiếu đến tham chiếu sẽ biến mất, nhưng không tham chiếu. Đây là mục đích để truyền tham số tham chiếu.

Một điều bạn nên biết, các loại giá trị được lưu trữ tại chỗ (không có địa chỉ bộ nhớ, thay vào đó chúng được lưu trực tiếp nơi địa chỉ bộ nhớ - Xem # 1). Khi chúng được truyền cho một phương thức, một bản sao được tạo và bản sao đó được sử dụng trong phương thức. Khi chúng được truyền qua tham chiếu, một địa chỉ bộ nhớ được truyền mà định vị kiểu giá trị trong bộ nhớ, cho phép nó được thay đổi.

Chỉnh sửa: Như dlev đã chỉ ra, những câu trả lời này không phải là quy tắc cứng và nhanh, vì không có quy tắc nào cho biết đây là cách phải. .NET là miễn phí để thực hiện những câu hỏi này tuy nhiên nó muốn. Đây là cách có khả năng nhất để thực hiện nó mặc dù, vì đây là cách làm việc của Intel CPU trong nội bộ, do đó, bằng cách sử dụng bất kỳ phương pháp khác có thể sẽ không hiệu quả.

Hy vọng tôi không nhầm lẫn bạn quá nhiều, nhưng vui lòng hỏi xem bạn có cần làm rõ hay không.

+0

Các loại giá trị không phải lúc nào cũng được lưu trữ trên ngăn xếp. –

+2

"loại giá trị được lưu trữ trên ngăn xếp": điều đó không đúng.Các loại giá trị ** có thể ** được lưu trữ trên ngăn xếp, nhưng không phải lúc nào cũng như vậy. Ví dụ. một trường kiểu giá trị trong một kiểu tham chiếu được lưu trữ trên heap, trong đối tượng mà nó thuộc về. 1 anyway, bởi vì câu trả lời của bạn chủ yếu là chính xác ... –

+0

@ThomasLevesque: Đã xóa tham chiếu đến các loại giá trị trên ngăn xếp. Cảm ơn! –

13

.NET Heaps and Stacks Đây là cách xử lý triệt để cách chồng và đống hoạt động.

C# và nhiều ngôn ngữ OOP sử dụng chung khác sử dụng chung Xử lý không phải con trỏ cho tham chiếu trong ngữ cảnh này (C# cũng có khả năng sử dụng con trỏ!) mô hình phân tích cho các câu hỏi như thế này. Xem bài viết tuyệt vời của Eric Lippert về chủ đề này Handles are Not Addresses

Không thích hợp để nói rằng Handle là kích thước của con trỏ. (mặc dù tình cờ có thể giống nhau) Xử lý là bí danh cho các đối tượng, không bắt buộc chúng là một địa chỉ chính thức đối với một đối tượng.

Trong trường hợp này xảy ra CLR để sử dụng các địa chỉ thực sự cho xử lý: Từ liên kết ở trên:

... CLR thực sự không thực hiện tham chiếu đối tượng quản lý như địa chỉ các đối tượng thuộc sở hữu của nhà sưu tập rác , nhưng đó là chi tiết triển khai .

Vì vậy, có một tay cầm có lẽ là 4 byte trên một kiến ​​trúc 32 bit, và 8 byte trên một kiến ​​trúc 64 byte, nhưng đây không phải là "chắc chắn", và nó là không trực tiếp vì con trỏ. Nó đáng chú ý tùy thuộc vào việc thực hiện trình biên dịch và phạm vi địa chỉ được sử dụng một số loại con trỏ có thể khác nhau về kích thước.

Với tất cả ngữ cảnh này, bạn có thể mô hình hóa điều này bằng cách tương tự con trỏ, nhưng điều quan trọng là phải nhận ra Handles không bắt buộc phải là địa chỉ. CLR có thể chọn để thay đổi điều này nếu nó muốn trong tương lai và người tiêu dùng của CLR không nên biết bất kỳ tốt hơn.

Một ổ cuối cùng của điểm tinh tế này:

Đây là một C# Pointer:

int* myVariable; 

Đây là một C# Xử lý:

object myVariable; 

Họ là không giống nhau.

Bạn có thể làm những việc như toán trên con trỏ, mà bạn không nên làm với Xử lý. Nếu xử lý của bạn xảy ra được thực hiện giống như một con trỏ và bạn sử dụng nó như thể nó là một con trỏ bạn đang sử dụng sai Handle trong một số cách mà có thể giúp bạn gặp rắc rối sau này.

+3

Đó không phải là một con trỏ C# vì nó là bất hợp pháp để tạo một con trỏ tới một kiểu tham chiếu được quản lý. 'int *' sẽ là một ví dụ về kiểu con trỏ C#. –

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