2010-01-08 35 views
6

Chúng tôi có một tình huống mà chúng tôi đang xem xét buộc một bộ sưu tập rác trên một máy chủ đó là rất thấp trên RAM (3,6/4GB sử dụng trên trung bình). Không, nó không thực sự là một lựa chọn để nâng cấp máy chủ này không may..NET Garbage Collection - Nó ảnh hưởng như thế nào?

Một trong các quy trình dịch vụ của chúng tôi (được viết gián tiếp bằng C++ (không hỏi ...)) hoạt động với các thành phần .NET và sau đó ngủ trong 10 phút. Khi dịch vụ đó đang ngủ, nó thường được treo trên bộ nhớ RAM 600MB có thể được chia sẻ với các quá trình khác. Có vẻ như bằng cách nào đó liên quan đến WSE truy tìm được bật để gỡ lỗi. Tôi có thể xem nó thức dậy và GC trên lần lặp tiếp theo trên cuộc gọi COM đầu tiên đến .NET - tuy nhiên quá trình này thực hiện một số công việc và vào thời điểm nó chuyển sang chế độ ngủ, RAM sử dụng được khoảng 600MB ... tốt, bạn có thể nhìn thấy nơi này đi ...

Câu hỏi: Tôi đang xem xét thêm bộ sưu tập rác ngay trước khi quá trình chuyển sang chế độ ngủ. Có các dịch vụ khác trên hộp này đang thực hiện các tác vụ liên quan .NET. Khi tôi gọi một bộ sưu tập rác trong quy trình dịch vụ này, liệu GC đó có ảnh hưởng đến tất cả các quy trình liên quan đến .NET khác trên hộp hay chỉ là quy trình yêu cầu bộ sưu tập? Tôi hơi lo lắng về việc tạo ra một số loại vấn đề hiệu suất cho các quy trình bên ngoài quy trình mà tôi quan tâm.

+4

Là một sang một bên, nếu bạn đang nắm giữ 600 MB tài nguyên quản lý .NET trong 10 phút, buộc một thu gom rác thải có thể không giải phóng tài nguyên. Chúng vẫn có thể được giữ bởi một cái gì đó trong quá trình .NET. Bạn có chắc chắn bạn không có bất kỳ tham chiếu hoạt động nào cho các tài nguyên đó treo quanh không? –

+0

Có tham chiếu đang hoạt động đối với lớp làm cho các cuộc gọi dịch vụ web. Tuy nhiên, mã C++ đang gọi một hàm ở phía .NET trả về một chuỗi. Không có các vars toàn cầu trong lớp. Tất cả các biến sẽ nằm ngoài phạm vi ngay sau khi cuộc gọi WS hoàn tất và chuỗi được trả về ứng dụng C++. – TheToasterThatCould

+0

chỉ muốn nói lời cảm ơn đến tất cả mọi người đã đóng góp ... các bạn thật tuyệt vời !! – TheToasterThatCould

Trả lời

10

Nó sẽ chỉ ảnh hưởng đến quá trình đang gọi GC.

+0

Một tham chiếu cho điều này sẽ rất tiện lợi. Các tài liệu tôi đã có thể tìm thấy nói rằng GC có thể ảnh hưởng đến tất cả các lĩnh vực ứng dụng hoặc chỉ một. Tôi sẽ giả định rằng khi bạn ép buộc nó, nó sẽ chỉ ảnh hưởng đến người gọi, nhưng thật tuyệt khi thấy điều đó. –

+2

AppDomain! = Quy trình. AppDomain là một cấu trúc .NET bên trong có các thiết lập bảo mật khác nhau, heap, vv Nó gần như là một quá trình nhỏ có thể được sử dụng để tải các plugin với các thiết lập bảo mật khác nhau, v.v. –

+0

Điểm tốt - Tôi quên mất nhiều AppDomain trong một tiến trình. –

4

Ngoài việc sử dụng CPU bổ sung trong suốt thời gian thu thập, việc buộc thu thập rác không dẫn đến ảnh hưởng đến các quy trình .NET khác. Tuy nhiên, buộc một bộ sưu tập rác sẽ không - trong hầu hết các trường hợp - dẫn đến việc giải phóng bộ nhớ vật lý.

Việc ánh xạ bộ nhớ vật lý tới không gian địa chỉ của quy trình là một điều phức tạp. Một bộ sưu tập rác trong một tiến trình .NET có thể tăng không gian trống trong vùng được quản lý - nhưng nó không đảm bảo dẫn đến giảm kích thước bộ làm việc (bộ nhớ mà quá trình Win32 của bạn được đưa ra từ hệ điều hành). Ngay cả khi bạn có thể có được một kế hoạch như vậy làm việc - nó sẽ là mong manh ở tốt nhất, và có thể không làm việc trong mọi hoàn cảnh.

Có một phương pháp Win32 được gọi là SetProcessWorkingSetSize() cho phép bạn kiểm soát bộ nhớ vật lý tối thiểu và tối đa được cấp phát cho quy trình. Bạn có thể muốn xem xét điều này kết hợp với chương trình thu hồi bắt buộc mà bạn đang khám phá.

8

Nó chỉ ảnh hưởng đến quá trình được gọi (nhưng sẽ ảnh hưởng đến tất cả Application Domains trong quá trình này). Tuy nhiên, được cảnh báo rằng điều này sẽ không giải phóng bộ nhớ cho hệ điều hành. Nếu bạn muốn giải phóng bộ nhớ cho hệ điều hành, một cách để làm điều đó là:

private static void minimizeMemory() 
{ 
    GC.Collect(GC.MaxGeneration); 
    GC.WaitForPendingFinalizers(); 
    SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, 
     (UIntPtr) 0xFFFFFFFF, (UIntPtr) 0xFFFFFFFF); 
} 

[DllImport("kernel32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
private static extern bool SetProcessWorkingSetSize(IntPtr process, 
    UIntPtr minimumWorkingSetSize, UIntPtr maximumWorkingSetSize); 

The caveat lớn ở đây là tại sao . Trừ khi bạn nhận thấy rằng bộ nhớ là đập hoặc hoán đổi là một nút cổ chai hiệu suất (hoặc bạn đang viết một ứng dụng người dùng cuối), không có lý do thực sự để được quan tâm về việc sử dụng bộ nhớ. Buộc GC có thể chậm. Giảm đống sẽ gây ra đống cần được phân bổ lại từ VM. Ngoài ra, .NET GC là phản ứng, sử dụng hành vi của chương trình để tăng hiệu quả của nó. Bằng cách buộc một bộ sưu tập, bạn không cho phép GC tự điều chỉnh hành vi của chương trình của bạn, tiếp tục giảm hiệu suất.

Tôi biết điều này từ kinh nghiệm - Tôi đã hỏi this question một thời gian và thậm chí đã đưa ra một lớp dựa trên bộ đếm thời gian để gọi phương thức ở trên sau khi thoát hoạt động bộ nhớ cao (chạy sau 5 phút). Sau này, quá trình làm việc thiết lập sẽ làm giảm chính nó rất nhiều - bằng cách trao đổi nó vào đĩa. Trong vài giây tiếp theo, nó sẽ đọc lại các phần được sử dụng thường xuyên nhất, một vài phút sau đó (khi nhiệm vụ được chạy lại), nó sẽ lại thực hiện một loạt phân bổ. Thời gian (thậm chí không profiling) quá trình cho thấy rằng với bộ sưu tập, đã có khoảng 0.2s (!) Chậm lại trong việc phân bổ VM từ hệ điều hành cho nhiệm vụ.

+0

Lý do tại sao ... quá trình dịch vụ này cần phải chạy sau mỗi 10 phút. Hộp này cũng có một dịch vụ tương tác (sorta như citrix ... nhưng khác nhau) cho phép người dùng kết nối. Tuy nhiên, khi máy chủ chạy thấp trên ram, rằng citrix như dịch vụ sẽ không cho phép kết nối mới. – TheToasterThatCould

+0

Ah, tôi hiểu rồi. Sau đó, thực sự, bạn sẽ muốn được quá trình giảm kích thước thiết lập làm việc thay vì chỉ làm một GC (mà chỉ compacts đống trong quá trình này). –

5

Bạn sẽ khôn ngoan để có được một profiler ra và xem tại sao các đối tượng không được thu gom rác thải hiệu quả. Nó có thể là họ kết thúc trong gen2 không cần thiết và bạn có thể refactor nó để cho phép nó để thoát khỏi các đối tượng nhanh hơn. Bạn cũng có thể thử đảm bảo phần .NET chạy với phiên bản máy chủ của bộ thu gom rác, mặc định là phiên bản máy trạm và điều này thích giữ cho quá trình hoạt động hơn là chạy GC (tức là nó được điều chỉnh để giữ một giao diện người dùng). đáp ứng). Phiên bản máy chủ tích cực hơn và chạy các GC song song, mỗi lõi một lần.

Thêm dòng sau vào app.config:

<Configuration> 
    <runtime> 
     <gcServer enabled=“true“ /> 
    </runtime> 
</Configuration> 

Linky để more information

2

Cùng với câu trả lời khác đề cập trực tiếp đến việc bạn sử dụng GC.Collect, tôi sẽ đề nghị bạn không chỉ làm một số hồ sơ đơn giản, nhưng cũng làm một đánh giá mã và đảm bảo rằng bạn đang phát hành đúng tài nguyên khi bạn sử dụng xong chúng.

Bạn có gọi là Vứt bỏ trên tất cả các đối tượng triển khai IDisposable khi bạn đang sử dụng chúng không? Nếu bạn có các lớp có chứa các biến riêng tư thực hiện IDisposable, thì lớp chứa có triển khai IDisposable và bạn có gọi là Dispose không?

Có những nơi bạn có thể sử dụng tuyên bố sử dụng để đảm bảo Vứt bỏ được gọi không? Không ai trong số những thứ này sẽ giúp đỡ với bộ nhớ vật lý, nhưng nó sẽ giúp với những thứ như HANDLE để cửa sổ đối tượng, vv

+0

Tôi sẽ hơi ngạc nhiên nếu vấn đề liên quan đến vấn đề này, nhưng tôi sẽ kiểm tra. Các trình cắm thêm COM .NET mà chúng tôi đang gọi đang chạy các hàm đơn giản thực hiện cuộc gọi dịch vụ web và trả về một chuỗi (xml từ ws chung). Không có biến toàn cục hoặc đối tượng không được quản lý mà tôi biết. – TheToasterThatCould

+0

COM? Sau đó, bạn sẽ muốn xem liệu các thành phần COM đang được phát hành đúng cách hay chưa. Bạn có cần thực hiện bất kỳ cuộc gọi thủ công nào tới Marshal.AddRef và Marshall.ReleaseComObject không? – Nick

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