2012-02-18 33 views
6

Xem các phiên bản loại giá trị mới được tạo mỗi khi chúng được chuyển làm đối số, tôi bắt đầu suy nghĩ về các trường hợp sử dụng các từ khóa ref hoặc out có thể hiển thị cải thiện hiệu suất đáng kể.Lợi ích của các loại giá trị trên các loại tham chiếu?

Sau một thời gian nó đánh tôi trong khi tôi thấy thâm hụt sử dụng các loại giá trị tôi không biết về bất kỳ lợi thế nào.
Vì vậy, câu hỏi của tôi là khá thẳng về phía trước - mục đích của việc có các loại giá trị là gì? những gì chúng ta đạt được bằng cách sao chép một cấu trúc thay vì chỉ tạo một tham chiếu mới cho nó?

Dường như với tôi rằng sẽ dễ dàng hơn nhiều nếu chỉ có các loại tham chiếu như trong Java.

Chỉnh sửa: Chỉ cần xóa mục này, tôi không đề cập đến các loại giá trị nhỏ hơn 8 byte (kích thước tối đa của tham chiếu), mà là loại giá trị từ 8 byte trở lên.

Ví dụ: cấu trúc Rectangle chứa bốn giá trị int.

+0

Java thực sự chỉ có các loại tham chiếu? –

+5

Một mảng gồm một triệu byte mất bao nhiêu byte nếu chúng là các loại giá trị? Bao nhiêu nó mất lên nếu họ là loại tài liệu tham khảo? –

+0

Có. Điều này thực sự đôi khi đi lên như là một vấn đề. Ngay cả DateTime cũng là một đối tượng. – usr

Trả lời

12
  • Ví dụ về loại giá trị một byte chiếm một byte. Loại tham chiếu chiếm không gian cho tham chiếu cộng với khối đồng bộ hóa và bảng chức năng ảo và ...

  • Để sao chép tham chiếu, bạn sao chép tham chiếu byte bốn (hoặc tám). Để sao chép một số nguyên bốn byte, bạn sao chép một số nguyên bốn byte. Sao chép các loại giá trị nhỏ không đắt hơn sao chép tài liệu tham khảo.

  • Các loại giá trị không chứa tham chiếu không cần phải được kiểm tra bởi bộ thu gom rác. Mọi tài liệu tham khảo phải được theo dõi bởi bộ thu gom rác.

+1

Địa phương tham chiếu cũng là một giao dịch lớn. –

+0

Tôi nên làm cho nó rõ ràng ngay lập tức, nhưng tôi đã đề cập đến các loại giá trị lớn hơn kích thước của một tham chiếu. Giới thiệu về điểm thứ ba của bạn: không phải là tham chiếu phương thức cục bộ bị hủy tự động khi phương thức kết thúc; giống như một cấu trúc? – Acidic

+0

@Acidic: Chắc chắn, tham chiếu * bị hủy. Nhưng * điều được nhắc đến * có thể không có; cái gì khác có thể được tham chiếu nó. –

3

"Tạo tham chiếu" không phải là vấn đề. Đây chỉ là một bản sao của 32/64 bit. Tạo đối tượng là tốn kém. Trên thực tế việc tạo ra các đối tượng là giá rẻ nhưng thu thập nó không phải là.

Loại giá trị tốt cho hiệu suất khi chúng nhỏ và bị loại bỏ thường xuyên. Chúng có thể được sử dụng trong các mảng lớn rất hiệu quả. Cấu trúc không có tiêu đề đối tượng. Có rất nhiều các khác biệt về hiệu suất khác.

Chỉnh sửa: Eric Lippert đặt ra một ví dụ tuyệt vời trong nhận xét: "Có bao nhiêu byte một mảng một triệu byte mất nếu chúng là loại giá trị? Số lượng mất bao nhiêu nếu chúng là loại tham chiếu?"

Tôi sẽ trả lời: Nếu cấu trúc đóng gói được đặt thành 1 mảng như vậy sẽ mất 1 triệu và 16 byte (trên hệ thống 32 bit). Sử dụng các loại tài liệu tham khảo nó sẽ mất:

array, object header: 12 
array, length: 4 
array, data: 4*(1 million) = 4m 
1 million objects, headers = 12 * (1 million) 
1 million objects, data padded to 4 bytes: 4 * (1 million) 

Và đó là lý do tại sao sử dụng các loại giá trị trong mảng lớn thể là một ý tưởng tốt.

2

Mức tăng được hiển thị nếu dữ liệu của bạn nhỏ (< 16 byte), bạn có nhiều trường hợp và/hoặc bạn thao tác chúng rất nhiều, đặc biệt là chuyển đến hàm. Điều này là do việc tạo một đối tượng tương đối đắt so với việc tạo ra một thể hiện kiểu giá trị nhỏ. Và như một người khác chỉ ra, các đối tượng cần phải được thu thập và thậm chí còn đắt hơn. Ngoài ra, các loại giá trị rất nhỏ có ít bộ nhớ hơn so với loại tương đương của loại tham chiếu.

Ví dụ về loại giá trị không nguyên thủy trong .NET là cấu trúc điểm (System.Drawing).

2

Giá trị các loại thường performant hơn các loại tài liệu tham khảo:

  • Một tài liệu tham khảo chi phí loại thêm bộ nhớ cho các tài liệu tham khảo và hiệu suất khi dereferencing

  • Một kiểu giá trị không cần thêm rác bộ sưu tập. Nó được thu thập rác cùng với cá thể nó sống. Các biến địa phương trong các phương thức được làm sạch khi phương thức rời khỏi.

  • Mảng giá trị hiệu quả kết hợp với bộ đệm. (Hãy suy nghĩ về một mảng ints so với một loạt các trường hợp loại Integer)

1

Mọi biến đều có vòng đời. nhưng không phải mọi biến cần sự linh hoạt cho biến của bạn để thực hiện cao nhưng không được quản lý trong heap.

Loại giá trị (Struct) chứa dữ liệu của chúng được phân bổ theo xếp chồng hoặc được phân bổ nội dòng trong cấu trúc. Các kiểu tham chiếu (Class) lưu trữ một tham chiếu đến địa chỉ bộ nhớ của giá trị, và được cấp phát trên heap.

mục đích của việc có các loại giá trị là gì? Các loại giá trị khá hiệu quả để xử lý dữ liệu đơn giản, (Nó nên được sử dụng để thể hiện các loại bất biến để biểu thị giá trị)

Không thể phân bổ đối tượng loại giá trị trên đống rác và biến đại diện đối tượng không chứa một con trỏ đến một đối tượng; biến chứa chính đối tượng đó.

chúng ta thu được gì bằng cách sao chép cấu trúc thay vì chỉ tạo tham chiếu mới cho cấu trúc đó?

Nếu bạn sao chép cấu trúc, C# tạo bản sao mới của đối tượng và gán bản sao của đối tượng cho một cá thể struct riêng biệt. Tuy nhiên, nếu bạn sao chép một lớp, C# tạo một bản sao mới của tham chiếu đến đối tượng và gán bản sao của tham chiếu đến cá thể lớp riêng biệt. Structs không thể có destructors, nhưng các class có thể có destructors.

+0

cảm ơn oleksii, để chỉnh sửa, cổ vũ, T –

1

Một lợi thế lớn của các loại giá trị như Rectangle là nếu người ta n địa điểm lưu trữ của loại Rectangle, người ta có thể chắc chắn rằng người ta có n trường hợp riêng biệt của loại Rectangle. Nếu có một mảng loại Rectangle, dài ít nhất là hai, một tuyên bố như MyArray[0] = MyArray[1] sẽ sao chép các trường của MyArray[1] vào các trường của MyArray[0], nhưng chúng sẽ tiếp tục tham chiếu đến các trường hợp riêng biệt Rectangle. Nếu một sau đó thực hiện một dòng lệnh MyArray[0].X += 4 sẽ sửa đổi trường X của một cá thể, mà không sửa đổi giá trị X của bất kỳ vị trí mảng nào khác hoặc Rectangle trường hợp. Lưu ý, bằng cách này, mà tạo ra các mảng ngay lập tức populates nó với ghi Rectangle trường hợp.

Hãy tưởng tượng nếu Rectangle là loại lớp có thể thay đổi.Việc tạo một mảng các trường hợp Rectangle có thể thay đổi sẽ yêu cầu một mảng thứ nhất đầu tiên, và sau đó gán cho mỗi phần tử trong mảng một thể hiện Rectangle mới. Nếu người ta muốn sao chép giá trị của một cá thể hình chữ nhật sang một trường hợp hình chữ nhật khác, người ta sẽ phải nói một cái gì đó như MyArray[0].CopyValuesFrom(MyArray[1]) [tất nhiên, sẽ thất bại nếu MyArray[0] không được điền với một tham chiếu đến một cá thể mới). Nếu một người vô tình nói MyArray[0] = MyArray[1], thì hãy viết thư đến MyArray[0].X cũng sẽ ảnh hưởng đến MyArray[1].X. Thứ dơ bẩn.

Điều quan trọng cần lưu ý là có một vài nơi trong C# và vb.net, nơi trình biên dịch sẽ ngầm sao chép một loại giá trị và sau đó hành động dựa trên bản sao như bản gốc. Đây là một thiết kế ngôn ngữ thực sự không may, và đã nhắc một số người đưa ra đề xuất rằng các loại giá trị sẽ không thay đổi (vì hầu hết các tình huống liên quan đến việc sao chép ngầm chỉ gây ra vấn đề với các loại giá trị có thể thay đổi). Quay lại khi trình biên dịch rất xấu khi cảnh báo các trường hợp bản sao ngữ nghĩa không rõ ràng sẽ mang lại hành vi bị hỏng, ý niệm như vậy có thể là hợp lý. Nó được coi là lỗi thời ngày hôm nay, mặc dù, bất kỳ trình biên dịch hiện đại nào cũng sẽ đánh dấu các lỗi trong hầu hết các kịch bản mà việc sao chép ngầm sẽ tạo ra các ngữ nghĩa bị hỏng, bao gồm tất cả các kịch bản mà cấu trúc chỉ bị biến đổi thông qua các hàm tạo, các bộ định vị thuộc tính hoặc các phép gán bên ngoài . Một tuyên bố như MyArray[0].X += 5 dễ đọc hơn nhiều so với MyArray[0] = new Rectangle(MyArray[0].X + 5, MyArray[0].Y, MyArray[0].Width, MyArray[0].Height).

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