2009-08-24 36 views
7

Ở đây có nhiều người đang bối rối,CLR lưu trữ các lớp tĩnh ở đâu?

Lớp thông thường lưu trữ dữ liệu của nó trong vùng heap phải không? Và tham chiếu (Pointer) vào ngăn xếp.

Khi ngăn xếp nằm ngoài phạm vi, Lần sau, trình thu gom rác sẽ khởi động và xóa bộ nhớ khỏi vùng heap.

Bây giờ trong trường hợp các lớp tĩnh, bộ nhớ không thể xóa sạch bởi bộ thu gom rác vì cần phải có toàn bộ chương trình. Và không có cách nào để lấy tài liệu tham khảo ngay từ đầu.

Vì vậy, khi chúng tôi gọi Console. Viết, ví dụ? Chương trình lấy tài liệu tham khảo từ đâu (Trường hợp nào lưu trữ tham chiếu đến lớp tĩnh)? Hoặc nó chỉ gọi nó trực tiếp, nhưng làm thế nào?

+4

Tôi không hiểu bất kỳ phần nào của câu hỏi này. Bạn có ý nghĩa gì bởi "giá trị của nó" và "ref của nó"? –

+0

Tôi hy vọng anh ấy đang nói về cách nó tách mã thực thi khỏi các thành viên dữ liệu. –

+1

Trong số các vấn đề khác, đó là "của nó". – jason

Trả lời

16

Tôi nghĩ rằng bạn đang nhầm lẫn các lớp học với trong đó thời gian sử dụng bộ nhớ với cách giữ bộ nhớ. Khi bạn tạo một thể hiện của một lớp bình thường, bộ nhớ của cá thể đó tồn tại trên heap. Tài liệu tham khảo đối với trường hợp này có thể nằm trong đối tượng trên heap (nếu bạn đặt biến thành viên bên trong một đối tượng khác của đối tượng vào nó); hoặc một biến ngăn xếp (nếu bạn khai báo một biến cho đối tượng bên trong một phương thức hoặc truyền cho một hàm gọi), hoặc nó có thể nằm trong danh sách các rễ toàn cầu (nếu nó là một tham chiếu tĩnh, ví dụ như một tham chiếu Singleton).

Không thể khởi tạo lớp tĩnh. Không có "tham chiếu" cho lớp ở bất kỳ đâu (ngoại trừ thông tin kiểu). Các phương thức của nó chỉ là các hàm được nạp vào bộ nhớ khi CLR nạp assembly. Bạn có thể tạo một delegate trỏ đến một trong những phương thức này, nhưng điều đó cũng không tạo ra một tham chiếu tới một cá thể lớp. Đó chỉ là một con trỏ đến một hàm.

Ví dụ, nhìn vào mã này:

class ObjectWrapper 
{ 
    Object obj = new Object(); 
} 

static void Main(string[] args) 
{ 
    ObjectWrapper wrapper = new ObjectWrapper(); 
    ... 
} 

Phương pháp chính tạo ra một thể hiện của một lớp ObjectWrapper. Ví dụ này tồn tại trên heap.

Bên trong cá thể ObjectWrapper, có một cá thể của đối tượng lớp đang tồn tại trên vùng heap. Tham chiếu đến lớp này là bên trong thể hiện, vì vậy tôi đoán bạn có thể nghĩ đến tham chiếu là "sống trong đống".

Bây giờ, so sánh này để đoạn mã sau:

class Singleton 
{ 
    static readonly instance = new Singleton(); 
} 

Các thể hiện của đối tượng Singleton sống trên đống, quá. Tuy nhiên, tham chiếu là tham chiếu tĩnh. Nó được CLR duy trì trong một danh sách các tham chiếu toàn cục hoặc "root".

Bây giờ nhìn vào lớp tĩnh này:

class ObjectWrapper 
{ 
    Object obj = new Object(); 
} 

static class HelperMethods 
{ 
    static int DoSomethingUseful(ObjectWrapper wrapper1) 
    { 
     ObjectWraper wrapper2 = wrapper1; 
     // code here 
    } 
} 

HelperMethods là một lớp tĩnh. Bạn không thể khởi tạo lớp HelperMethods. Không thể có bất kỳ đối tượng nào từ lớp này trên heap. Tuy nhiên, trong phương thức DoSomethingUseful, nó có hai tham chiếu đến một cá thể của lớp ObjectWrapper trên ngăn xếp. Một được thông qua, và một được khai báo bên trong phương thức.

+0

+1, rất thích chi tiết. – user7116

+0

Theo như "rễ" đi, hãy xem bài viết này giải thích thuật toán GC của .NET và làm rõ cách mà rễ có vai trò trong GC. http://msdn.microsoft.com/en-us/magazine/bb985010.aspx – felideon

+0

Có một vài điểm trong câu trả lời này không hoàn toàn chính xác. Đối với một, câu lệnh 'Không có "tham chiếu" ở bất cứ đâu' không chính xác. Một tham chiếu đến mọi loại, tĩnh hoặc khác, được tổ chức trên một đống bộ nạp. Toàn bộ hệ thống kiểu được quản lý trên một đống bộ nạp, với các tham chiếu đến các kiểu và các thành viên của chúng. Ngoài ra, 'Lớp này sẽ không bao giờ tiêu thụ bộ nhớ trên heap' là không chính xác là tốt ... trong khi nó không tiêu thụ không gian GC heap, nó KHÔNG tiêu thụ không gian heap trên một đống bộ nạp. Ý tưởng về một tham chiếu đơn giản là một con trỏ cũng không chính xác ... CLR sử dụng nhiều mức độ bất định. – jrista

6

Để cung cấp cho bạn một câu trả lời đơn giản, các lớp tĩnh được "lưu trữ" trên cái được gọi là Hacker tải.Hốc nạp là những vết thương đặc biệt, không phải GC có tỷ lệ tăng trưởng cực kỳ có thể dự đoán và nghiêm ngặt. Khi một ứng dụng .NET khởi động, một số AppDomain được tạo ra. Ngoài miền ứng dụng chính, có miền hệ thống và miền ứng dụng được chia sẻ có chứa các vùng tên hệ thống và mscorelib, các vùng đặc biệt (chẳng hạn như vùng bộ nạp) và bản thân CLR.

Đối với một lời giải thích đầy đủ chi tiết, đọc bài viết Tạp chí MSDN sau đây:

Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects

Mặc dù là từ một vài năm trước đây, nó vẫn được áp dụng. (Tuy nhiên, tôi không thể nói nếu .NET 4.0 đã thay đổi nhiều điều này.)

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