2009-03-03 37 views
13

Khi bạn cần có các đối tượng rất nhỏ, có chứa 2 thuộc tính float, và bạn sẽ có hàng triệu đối tượng không bị "hủy" ngay lập tức. hoặc các lớp học?Cấu trúc vs Lớp đối tượng sống lâu

Giống như trong thư viện xna, có các điểm 3, v.v ... nhưng nếu bạn cần giữ các giá trị đó trong một thời gian dài, liệu nó có gây ra mối đe dọa về hiệu năng không?

Trả lời

33

Trái ngược với hầu hết các câu hỏi về cấu trúc, điều này thực sự có vẻ là một cách sử dụng tốt cấu trúc. Nếu dữ liệu nó chứa là các kiểu giá trị, và bạn sẽ sử dụng rất nhiều trong số này, một cấu trúc sẽ hoạt động tốt.

Một số mẹo:

:: Cấu trúc không được lớn hơn 16 byte hoặc bạn mất lợi thế về hiệu suất.

:: Làm cho cấu trúc không thay đổi. Điều đó làm cho việc sử dụng rõ ràng hơn.

Ví dụ:

public struct Point3D { 

    public float X { get; private set; } 
    public float Y { get; private set; } 
    public float Z { get; private set; } 

    public Point3D(float x, float y, float z) { 
     X = x; 
     Y = y; 
     Z = z; 
    } 

    public Point3D Invert() { 
     return new Point3D(-X, -Y, -Z); 
    } 

} 
+0

Bài đăng tuyệt vời, đã cập nhật cuối cùng của tôi hôm nay. –

+4

Đây có lẽ là cách sử dụng tốt từ khóa chỉ đọc, tức là thay vì khai báo X, Y và Z là thuộc tính, bạn có thể có các trường chỉ đọc. Lợi thế sẽ là bạn sẽ không phá vỡ bất biến của bạn do nhầm lẫn. – Ant

+0

Là 'myRect = new Rectangle (myRect.X, myRect.Y + 4, myRect.Width, myRect.Height);' thực sự rõ ràng hơn 'myRect.Y + = 4;'? Việc thay đổi * phương thức * cho các cấu trúc có vấn đề, nhưng các trường tiếp xúc phải là chuẩn trong nhiều trường hợp. – supercat

2

Mối quan tâm lớn là liệu bộ nhớ có được cấp phát trên ngăn xếp hay vùng lưu trữ hay không. Theo mặc định, các Structs đi vào ngăn xếp và ngăn xếp thường bị hạn chế nhiều hơn về mặt không gian. Vì vậy, việc tạo ra một loạt các cấu trúc giống như vậy có thể là một vấn đề.

Trong thực tế, mặc dù, tôi không thực sự nghĩ rằng đó là lớn của một thỏa thuận. Nếu bạn có nhiều người trong số họ có khả năng là một phần của một cá thể lớp (trên heap) ở đâu đó.

+1

Không gian ngăn xếp không phải là mối quan tâm đối với cấu trúc, vì bạn hiếm khi có nhiều biến cục bộ. Nếu bạn tạo một mảng các cấu trúc, nó sẽ được cấp phát trên heap, chứ không phải ngăn xếp. – Guffa

+0

Tôi nghĩ rằng đó là quan điểm của tôi: nếu bạn _do_ có nhiều vấn đề đó là một vấn đề, nhưng bạn không có khả năng có nhiều. –

+0

Nếu bạn có nhiều biến đó là một vấn đề bất kể nó là một cấu trúc hay một lớp, vì các tham chiếu cũng sẽ được cấp phát trên ngăn xếp ... :) – Guffa

1

Loại giá trị (cấu trúc) phù hợp với loại không được phân bổ thường xuyên trên heap, nghĩa là chúng hầu như được chứa trong một loại tham chiếu hoặc giá trị khác.

Ví dụ về Vector3 mà bạn đưa ra là một ví dụ hoàn hảo. Bạn sẽ hiếm khi có lủng lẳng Vector3 trong heap, họ sẽ hầu hết thời gian được chứa trong một loại đó là chính nó trong đống, hoặc được sử dụng như là một biến địa phương, trong trường hợp đó, nó sẽ được phân bổ trên ngăn xếp.

+0

Cảm ơn, vì vậy cấu trúc sẽ chỉ trên heap nếu được sử dụng như biến cục bộ và không có gì khác? –

+0

Không, đó là cách khác. Kiểu giá trị như cấu trúc chỉ được cấp phát trên ngăn xếp nếu đó là biến cục bộ. Nếu nó là một thành viên của một lớp, nó được phân bổ như là một phần của vùng bộ nhớ của đối tượng trên heap. – Guffa

2

Cấu trúc có vẻ phù hợp với ứng dụng này.

Hãy nhớ rằng "cần phải giữ các giá trị đó" ngụ ý lưu trữ của chúng trên heap ở đâu đó, có thể là một trường mảng của một cá thể lớp.

Một điều cần lưu ý là kết quả này được phân bổ trên vùng đối tượng lớn. Nó không rõ ràng làm thế nào, nếu ở tất cả, heap này defrags chính nó, tuy nhiên đối với các đối tượng sống rất dài mà có lẽ không phải là một vấn đề.

Sử dụng lớp cho hàng triệu loại dữ liệu này có thể sẽ tốn kém trong khối lượng cắt giảm của hội nghị truyền hình có khả năng sẽ diễn ra đối với các hoạt động trên loại này.

5

Câu trả lời phụ thuộc vào nơi các đối tượng/giá trị cuối cùng sẽ được lưu trữ. Nếu chúng được lưu trữ trong một bộ sưu tập không được phân loại như ArrayList, thì bạn sẽ kết thúc chúng. Boxing tạo ra một wrapper đối tượng cho một struct và dấu chân giống như với một đối tượng class. Mặt khác, nếu bạn sử dụng một mảng được đánh máy như T [] hoặc Danh sách, thì việc sử dụng cấu trúc sẽ chỉ lưu trữ dữ liệu thực tế cho mỗi phần tử với dấu chân cho toàn bộ bộ sưu tập chứ không phải các phần tử của nó.

Vì vậy, các cấu trúc có hiệu quả hơn để sử dụng trong các mảng T [].

2

Theo quy tắc, các mảng lớn không có biệt danh (tức làunshared) dữ liệu cùng loại được lưu trữ tốt nhất trong các cấu trúc cho hiệu suất vì bạn giảm số lượng các indirections. (Xem thêm when-are-structs-the-answer). Sự khác biệt hiệu suất chính xác giữa lớp và cấu trúc phụ thuộc vào cách sử dụng của bạn. (Ví dụ, trong các hoạt động, bạn chỉ truy cập vào các phần của cấu trúc? Bạn có thực hiện nhiều thao tác sao chép tạm thời không? Nếu cấu trúc nhỏ thì có lẽ tốt hơn nên sử dụng nhưng nếu nó lớn, việc tạo các bản sao tạm thời có thể làm chậm bạn. làm cho nó bất biến, bạn sẽ phải luôn luôn sao chép toàn bộ điều để thay đổi giá trị.)

Khi nghi ngờ, hãy đo lường.

Vì bạn quan tâm đến các hiệu ứng lâu dài có thể không rõ ràng bằng phép đo như vậy, hãy lưu ý rằng các mảng đó có thể được lưu trữ trên đống đối tượng lớn và phải được sử dụng lại thay vì bị phá hủy và quay lại được phân bổ. (xem CRL Inside Out: Large Object Heap Uncovered.)

Khi truyền các cấu trúc kích thước lớn hơn trong các cuộc gọi, bạn có thể muốn truyền chúng với đối số ref để tránh sao chép.

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