2012-01-26 16 views
21

Đây là ứng dụng dịch vụ .NET v4 windows đang chạy trên máy x64. Tại một số thời điểm sau những ngày chạy liên tục, mức tiêu thụ bộ nhớ dịch vụ Windows tăng đột biến như điên cho đến khi nó bị treo. Tôi đã có thể bắt nó ở 1,2 GB và chụp một bãi chứa bộ nhớ. Đây là những gì tôi nhận đượcCách phân tích <unclassified> sử dụng bộ nhớ trong windbg

Nếu tôi chạy! Giải quyết -summary trong windbg trên tập tin dump của tôi tôi nhận được kết quả sau

! Giải quyết -summary

--- Usage Summary ------ RgnCount ------- Total Size -------- %ofBusy %ofTotal 
Free      821  7ff`7e834000 ( 7.998 Tb)   99.98% 
<unclassified>   3696  0`6eece000 ( 1.733 Gb) 85.67% 0.02% 
Image     1851  0`0ea6f000 (234.434 Mb) 11.32% 0.00% 
Stack     1881  0`03968000 ( 57.406 Mb) 2.77% 0.00% 
TEB      628  0`004e8000 ( 4.906 Mb) 0.24% 0.00% 
NlsTables    1   0`00023000 (140.000 kb) 0.01% 0.00% 
ActivationContextData 3   0`00006000 ( 24.000 kb) 0.00% 0.00% 
CsrSharedMemory   1   0`00005000 ( 20.000 kb) 0.00% 0.00% 
PEB      1   0`00001000 ( 4.000 kb) 0.00% 0.00% 
- 
- 
- 
--- Type Summary (for busy) -- RgnCount ----- Total Size ----- %ofBusy %ofTotal 
MEM_PRIVATE      5837 0`7115a000 ( 1.767 Gb) 87.34% 0.02% 
MEM_IMAGE       2185 0`0f131000 (241.191 Mb) 11.64% 0.00% 
MEM_MAPPED       40 0`01531000 (21.191 Mb) 1.02% 0.00% 
- 
- 
--- State Summary ------------ RgnCount ------ Total Size ---- %ofBusy %ofTotal 
MEM_FREE       821 7ff`7e834000 ( 7.998 Tb)  99.98% 
MEM_COMMIT       6127 0`4fd5e000 ( 1.247 Gb) 61.66% 0.02% 
MEM_RESERVE      1935 0`31a5e000 (794.367 Mb) 38.34% 0.01% 
- 
- 
--Protect Summary(for commit)- RgnCount ------ Total Size --- %ofBusy %ofTotal 
PAGE_READWRITE      3412 0`3e862000 (1000.383 Mb) 48.29% 0.01% 
PAGE_EXECUTE_READ     220 0`0b12f000 (177.184 Mb) 8.55% 0.00% 
PAGE_READONLY      646 0`02fd0000 ( 47.813 Mb) 2.31% 0.00% 
PAGE_WRITECOPY      410 0`01781000 ( 23.504 Mb) 1.13% 0.00% 
PAGE_READWRITE|PAGE_GUARD   1224 0`012f2000 ( 18.945 Mb) 0.91% 0.00% 
PAGE_EXECUTE_READWRITE    144 0`007b9000 ( 7.723 Mb) 0.37% 0.00% 
PAGE_EXECUTE_WRITECOPY    70 0`001cd000 ( 1.801 Mb) 0.09% 0.00% 
PAGE_EXECUTE       1 0`00004000 ( 16.000 kb) 0.00% 0.00% 
- 
- 
--- Largest Region by Usage ----Base Address -------- Region Size ---------- 
Free       0`8fff0000  7fe`59050000 ( 7.994 Tb) 
<unclassified>     0`80d92000  0`0f25e000 (242.367 Mb) 
Image       fe`f6255000  0`0125a000 ( 18.352 Mb) 
Stack       0`014d0000  0`000fc000 (1008.000 kb) 
TEB        0`7ffde000  0`00002000 ( 8.000 kb) 
NlsTables      7ff`fffb0000  0`00023000 (140.000 kb) 
ActivationContextData   0`00030000  0`00004000 ( 16.000 kb) 
CsrSharedMemory     0`7efe0000  0`00005000 ( 20.000 kb) 
PEB        7ff`fffdd000  0`00001000 ( 4.000 kb) 

Thứ nhất, tại sao không được phân loại chương trình lên một lần 1,73 GB và thời gian khác là 242 MB. (Điều này đã được trả lời. Cảm ơn bạn)

Thứ hai, tôi hiểu rằng chưa được phân loại có thể có nghĩa là mã được quản lý, tuy nhiên kích thước heap của tôi theo! Eeheap chỉ 248 MB, thực sự khớp với 242 nhưng thậm chí không gần 1,73GB. Kích thước tệp kết xuất là 1,2 GB cao hơn nhiều so với bình thường. Tôi phải đi đâu từ đây để tìm hiểu xem cái gì đang sử dụng hết bộ nhớ. Bất cứ điều gì trong thế giới quản lý heap là dưới 248 MB, nhưng tôi đang sử dụng 1,2 GB.

Cảm ơn

EDIT

Nếu tôi làm! Đống -Si nhận được như sau

LFH Key     : 0x000000171fab7f20 
Termination on corruption : ENABLED 
      Heap  Flags Reserv Commit Virt Free List UCR Virt Lock Fast 
          (k)  (k) (k)  (k) length  blocks cont. heap 
------------------------------------------------------------------------------------- 
Virtual block: 00000000017e0000 - 00000000017e0000 (size 0000000000000000) 
Virtual block: 0000000045bd0000 - 0000000045bd0000 (size 0000000000000000) 
Virtual block: 000000006fff0000 - 000000006fff0000 (size 0000000000000000) 
0000000000060000 00000002 113024 102028 113024 27343 1542 11 3 1c LFH 
    External fragmentation 26 % (1542 free blocks) 
0000000000010000 00008000  64  4  64  1  1  1 0 0  
0000000000480000 00001002 3136 1380 3136  20  8  3 0 0 LFH 
0000000000640000 00041002  512  8 512  3  1  1 0 0  
0000000000800000 00001002 3136 1412 3136  15  7  3 0 0 LFH 
00000000009d0000 00001002 3136 1380 3136  19  7  3 0 0 LFH 
00000000008a0000 00041002  512  16 512  3  1  1 0 0  
0000000000630000 00001002 7232 3628 7232  18 53  4 0 0 LFH 
0000000000da0000 00041002 1536 856 1536  1  1  2 0 0 LFH 
0000000000ef0000 00041002 1536 944 1536  4 12  2 0 0 LFH 
00000000034b0000 00001002 1536 1452 1536  6 17  2 0 0 LFH 
00000000019c0000 00001002 3136 1396 3136  16  6  3 0 0 LFH 
0000000003be0000 00001002 1536 1072 1536  5  7  2 0 3 LFH 
0000000003dc0000 00011002  512 220 512 100 60  1 0 2  
0000000002520000 00001002  512  8 512  3  2  1 0 0  
0000000003b60000 00001002 339712 168996 339712 151494 976 116 0 18 LFH 
    External fragmentation 89 % (976 free blocks) 
    Virtual address fragmentation 50 % (116 uncommited ranges) 
0000000003f20000 00001002  64  8  64  3  1  1 0  0  
0000000003d90000 00001002  64  8  64  3  1  1 0  0  
0000000003ee0000 00001002  64  16  64  11  1  1 0  0  
------------------------------------------------------------------------------------- 
+0

Sử dụng tệp dll SOS và nhìn vào đống theo cách đó. Vì đây là một chương trình .net phân bổ đống được thực hiện bởi khung .net không hiển thị trong vùng không được quản lý. – Zipper

+0

kích thước heap của tôi theo! Eeheap (sos.dll) chỉ là 248 MB. Vì vậy, tôi không chắc chắn đó là nguyên nhân của kích thước quá trình 1,2 GB, cũng không phải nguyên nhân của 1,7 GB chưa phân loại, trừ khi tôi thiếu một cái gì đó – Mark

+0

Dịch vụ của bạn làm gì? Dịch vụ của bạn có chứa mã không được quản lý hoặc mã C++/CLI không? Nó trông giống như một rò rỉ bộ nhớ không được quản lý. GDI, đối tượng người dùng, số lượng xử lý nói gì? Trong đó ngăn xếp cuộc gọi là chủ đề của bạn bị mắc kẹt? ~ * e! ClrStack và ~ * e! DumpStack và ~ * ekv là bạn của bạn để xem chủ đề của bạn đang làm gì. Là một sợi ở giữa phân bổ một cái gì đó? –

Trả lời

2

“Tóm tắt sử dụng” nói rằng bạn có 3696 khu vực trên không được phân loại đưa ra một tổng cộng 17.33 Gb

"Vùng lớn nhất" cho biết rằng khu vực chưa được phân loại lớn nhất là 242 Mb. Phần còn lại của các vùng chưa được phân loại (3695 vùng) cùng nhau tạo nên sự khác biệt lên đến 17,33 Gb.

Cố gắng thực hiện một heap –s và tổng hợp dấu Virt để xem kích thước của vùng gốc, tôi nghĩ chúng cũng rơi vào nhóm không được quản lý. (Các phiên bản trước đó của NB hiển thị nội dung bản địa rõ ràng từ! Address -summary)

+0

Cảm ơn bạn đã giải thích về Tóm tắt sử dụng so với Vùng lớn nhất. Tôi đã làm một!đống-s và tổng cộng các đức hạnh col và tôi nhận được 359,12 MB. Điều đó có nói gì không? Tôi đã thêm các kết quả của! Heap -s – Mark

+0

Không xin lỗi, và vì đây là một bãi chứa 64 bit, tôi không có kinh nghiệm thực tế. Nhân tiện, phiên bản .NET là gì? Điều đó có thể được quan tâm cho người khác có thể biết thêm chi tiết –

+0

Tôi đã thêm thông tin đó vào mô tả câu hỏi của anh ấy. Đó là .NET 4.0 – Mark

1

Bạn đặt cược tốt nhất là sử dụng các lệnh EEHeap và GCHandles trong windbg (http://msdn.microsoft.com/en-us/ library/bb190764.aspx) và cố gắng xem liệu bạn có thể tìm thấy những gì có thể bị rò rỉ/sai theo cách đó hay không. Không may là bạn có thể sẽ không thể nhận được sự trợ giúp chính xác mà bạn đang tìm kiếm do thực tế việc chẩn đoán các loại vấn đề này hầu như luôn rất tốn thời gian và bên ngoài những trường hợp đơn giản nhất đòi hỏi ai đó phải làm đầy đủ phân tích trên bãi chứa. Về cơ bản nó không chắc rằng ai đó sẽ có thể chỉ cho bạn hướng tới một câu trả lời trực tiếp trên Stack tràn. Chủ yếu là mọi người sẽ có thể chỉ cho bạn các lệnh có thể hữu ích. Bạn sẽ phải làm rất nhiều việc đào bới để tìm hiểu thêm thông tin về những gì đang xảy ra.

+0

Nó sẽ đủ tốt để được chỉ ra đúng hướng. Giống như tôi đã nói EEHeap dường như chỉ mô tả 248 MB của toàn bộ điều, vì vậy tôi không chắc chắn nếu câu trả lời có thể được ở đó. Tôi sẽ xem xét GCHandles – Mark

16

Gần đây tôi đã có một tình huống rất giống nhau và đã tìm thấy một vài kỹ thuật hữu ích trong cuộc điều tra. Không ai là viên đạn bạc, nhưng mỗi viên đạn lại sáng hơn một chút về vấn đề này.

1) vmmap.exe từ SysInternals (http://technet.microsoft.com/en-us/sysinternals/dd535533) thực hiện tốt công việc liên quan đến thông tin về bộ nhớ gốc và bộ nhớ được quản lý và trình bày nó trong giao diện người dùng đẹp mắt. Các thông tin tương tự có thể được thu thập bằng cách sử dụng các kỹ thuật dưới đây, nhưng đây là cách dễ dàng hơn và một nơi tốt đẹp để bắt đầu. Đáng buồn thay, nó không hoạt động trên các tệp kết xuất, bạn cần một quy trình trực tiếp.

2) Đầu ra "! Address -summary" là một bản sao của đầu ra "địa chỉ" chi tiết hơn. Tôi thấy hữu ích khi thả đầu ra chi tiết vào Excel và chạy một số trục xoay. Sử dụng kỹ thuật này, tôi phát hiện ra rằng một số lượng lớn các byte được liệt kê là "" thực sự là các trang MEM_IMAGE, có thể là các bản sao của các trang dữ liệu được tải khi các tệp DLL được tải nhưng sau đó được sao chép khi dữ liệu được thay đổi. Tôi cũng có thể lọc đến các vùng lớn và đi sâu vào các địa chỉ cụ thể. Poking xung quanh trong bãi chứa bộ nhớ với một cây tăm và rất nhiều cầu nguyện là đau đớn, nhưng có thể được tiết lộ.

3) Cuối cùng, tôi đã làm phiên bản kỹ thuật vmmap.exe của người nghèo ở trên. Tôi đã tải lên tệp kết xuất, mở nhật ký và chạy địa chỉ!, Eeheap, heap, và! Tôi cũng nhắm mục tiêu các khối môi trường luồng được liệt kê trong ~ * k với! Teb. Tôi đã đóng tệp nhật ký và tải nó lên trong trình chỉnh sửa yêu thích của mình. Sau đó tôi có thể tìm một khối chưa được phân loại và tìm kiếm để xem liệu nó có xuất hiện ở đầu ra từ một trong các lệnh chi tiết hơn không. Bạn có thể khá nhanh chóng tương quan heaps bản địa và quản lý để loại bỏ những người ra khỏi khu vực nghi ngờ của bạn chưa được phân loại.

Đây là tất cả cách quá thủ công. Tôi rất thích viết một kịch bản mà sẽ có đầu ra tương tự như những gì tôi tạo ra trong kỹ thuật 3 ở trên và đầu ra một tập tin mmp phù hợp để xem vmmap.exe. Một ngày nào đó.

Một lưu ý cuối cùng: Tôi đã thực hiện mối tương quan giữa đầu ra của vmmap.exe với đầu ra địa chỉ !, và lưu ý các loại vùng này mà vmmap xác định từ nhiều nguồn khác nhau (tương tự như sử dụng heap và! Eeheap) không biết. Đó là, đây là những điều mà vmmap.exe dán nhãn nhưng địa chỉ không:

.data 
.pdata 
.rdata 
.text 
64-bit thread stack 
Domain 1 
Domain 1 High Frequency Heap 
Domain 1 JIT Code Heap 
Domain 1 Low Frequency Heap 
Domain 1 Virtual Call Stub 
Domain 1 Virtual Call Stub Lookup Heap 
Domain 1 Virtual Call Stub Resolve Heap 
GC 
Large Object Heap 
Native heaps 
Thread Environment Blocks 

Có vẫn còn rất nhiều "private" byte mất tích, nhưng một lần nữa, tôi có thể thu hẹp vấn đề nếu Tôi có thể loại bỏ chúng.

Hy vọng điều này sẽ cung cấp cho bạn một số ý tưởng về cách điều tra. Tôi đang ở trong cùng một chiếc thuyền vì vậy tôi cũng đánh giá cao những gì bạn tìm thấy. Cảm ơn!

+0

"Tôi muốn viết kịch bản ... để xem vmmap": bạn đã có cơ hội để làm như vậy chưa? –

1

tôi giữ một bản sao của Debugging Công cụ dành cho Windows 6.11.1.404 mà dường như để có thể hiển thị một cái gì đó có ý nghĩa hơn cho "không được phân loại"

Với phiên bản đó, tôi nhìn thấy một danh sách các địa TEB và sau đó này:

0:000> !address -summary 
--------- PEB fffde000 not found ---- 
TEB fffdd000 in range fffdb000 fffde000 
TEB fffda000 in range fffd8000 fffdb000 
...snip... 
TEB fe01c000 in range fe01a000 fe01d000 
ProcessParametrs 002c15e0 in range 002c0000 003c0000 
Environment 002c0810 in range 002c0000 003c0000 
-------------------- Usage SUMMARY -------------------------- 
    TotSize (  KB) Pct(Tots) Pct(Busy) Usage 
    41f08000 (1080352) : 25.76% 34.88% : RegionUsageIsVAD 
    42ecf000 (1096508) : 26.14% 00.00% : RegionUsageFree 
    5c21000 ( 94340) : 02.25% 03.05% : RegionUsageImage 
    c900000 ( 205824) : 04.91% 06.64% : RegionUsageStack 
      0 (  0) : 00.00% 00.00% : RegionUsageTeb 
    68cf8000 (1717216) : 40.94% 55.43% : RegionUsageHeap 
      0 (  0) : 00.00% 00.00% : RegionUsagePageHeap 
      0 (  0) : 00.00% 00.00% : RegionUsagePeb 
      0 (  0) : 00.00% 00.00% : RegionUsageProcessParametrs 
      0 (  0) : 00.00% 00.00% : RegionUsageEnvironmentBlock 
     Tot: ffff0000 (4194240 KB) Busy: bd121000 (3097732 KB) 

-------------------- Type SUMMARY -------------------------- 
    TotSize (  KB) Pct(Tots) Usage 
    42ecf000 (1096508) : 26.14% : <free> 
    5e6e000 ( 96696) : 02.31% : MEM_IMAGE 
    28ed000 ( 41908) : 01.00% : MEM_MAPPED 
    b49c6000 (2959128) : 70.55% : MEM_PRIVATE 

-------------------- State SUMMARY -------------------------- 
    TotSize (  KB) Pct(Tots) Usage 
    9b4d1000 (2544452) : 60.67% : MEM_COMMIT 
    42ecf000 (1096508) : 26.14% : MEM_FREE 
    21c50000 ( 553280) : 13.19% : MEM_RESERVE 

Largest free region: Base bc480000 - Size 38e10000 (931904 KB) 

Với phiên bản "hiện tại" (6.12.2.633) của tôi, tôi nhận được thông tin này từ cùng một bãi chứa. Hai điều tôi lưu ý:

Dữ liệu có vẻ là tổng của HeapAlloc/RegionUsageHeap và VirtualAlloc/RegionUsageIsVAD).

Lỗi EFAIL đáng yêu không nghi ngờ gì một phần chịu trách nhiệm về dữ liệu bị thiếu!

Tôi không chắc chắn làm thế nào mà tôi sẽ giúp bạn với mã quản lý của bạn, nhưng tôi nghĩ rằng nó thực sự trả lời cho câu hỏi ban đầu ;-)

0:000> !address -summary 


Failed to map Heaps (error 80004005) 

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal 
<unclassified>       7171   aab21000 ( 2.667 Gb) 90.28% 66.68% 
Free         637   42ecf000 ( 1.046 Gb)   26.14% 
Stack         603   c900000 (201.000 Mb) 6.64% 4.91% 
Image         636   5c21000 ( 92.129 Mb) 3.05% 2.25% 
TEB          201    c9000 (804.000 kb) 0.03% 0.02% 
ActivationContextData     14    11000 ( 68.000 kb) 0.00% 0.00% 
CsrSharedMemory       1    5000 ( 20.000 kb) 0.00% 0.00% 

--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal 
MEM_PRIVATE       7921   b49c6000 ( 2.822 Gb) 95.53% 70.55% 
MEM_IMAGE        665   5e6e000 ( 94.430 Mb) 3.12% 2.31% 
MEM_MAPPED        40   28ed000 ( 40.926 Mb) 1.35% 1.00% 

--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal 
MEM_COMMIT        5734   9b4d1000 ( 2.427 Gb) 82.14% 60.67% 
MEM_FREE        637   42ecf000 ( 1.046 Gb)   26.14% 
MEM_RESERVE       2892   21c50000 (540.313 Mb) 17.86% 13.19% 

--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal 
PAGE_READWRITE       4805   942bd000 ( 2.315 Gb) 78.37% 57.88% 
PAGE_READONLY       215   3cbb000 ( 60.730 Mb) 2.01% 1.48% 
PAGE_EXECUTE_READ      78   2477000 ( 36.465 Mb) 1.21% 0.89% 
PAGE_WRITECOPY       74   75b000 ( 7.355 Mb) 0.24% 0.18% 
PAGE_READWRITE|PAGE_GUARD    402   3d6000 ( 3.836 Mb) 0.13% 0.09% 
PAGE_EXECUTE_READWRITE     80   3b0000 ( 3.688 Mb) 0.12% 0.09% 
PAGE_EXECUTE_WRITECOPY     80   201000 ( 2.004 Mb) 0.07% 0.05% 

--- Largest Region by Usage ----------- Base Address -------- Region Size ---------- 
<unclassified>        786000   17d9000 ( 23.848 Mb) 
Free          bc480000   38e10000 (910.063 Mb) 
Stack          6f90000    fd000 (1012.000 kb) 
Image          3c3c000   ebe000 ( 14.742 Mb) 
TEB           fdf8f000    1000 ( 4.000 kb) 
ActivationContextData       190000    4000 ( 16.000 kb) 
CsrSharedMemory        7efe0000    5000 ( 20.000 kb) 
0

Gần đây tôi đã trải qua một thời gian chẩn đoán một vấn đề khách hàng nơi họ ứng dụng đã sử dụng 70GB trước khi chấm dứt (có khả năng do đạt giới hạn tái chế của IIS App Pool, nhưng vẫn chưa được xác nhận). Họ gửi cho tôi một bộ nhớ 35 GB. Dựa trên kinh nghiệm gần đây của tôi, dưới đây là một số quan sát tôi có thể thực hiện về những gì bạn đã cung cấp:

Trong đầu ra heap -s, 284 MB của 1,247 GB được hiển thị trong cột Cam kết. Nếu bạn đã mở bãi chứa này trong DebugDiag nó sẽ cho bạn biết rằng heap 0x60000 có bộ nhớ cam kết 1 GB.Bạn sẽ thêm kích thước cam kết của 11 phân đoạn được báo cáo và thấy rằng chúng chỉ thêm tối đa khoảng 102 MB chứ không phải 1GB. Rất khó chịu.

Bộ nhớ "thiếu" không bị thiếu. Nó thực sự ám chỉ ở đầu ra heap -s như là các dòng "Virtual block:". Không may, đống -s hút và không hiển thị địa chỉ kết thúc đúng cách và do đó báo cáo kích thước như 0. Kiểm tra đầu ra của các lệnh sau:

!address 17e0000 
!address 45bd0000 
!address 6fff0000 

Nó sẽ báo cáo các địa chỉ kết thúc thích hợp và do đó một chính xác " Kích thước khu vực ". Thậm chí tốt hơn, nó cho một phiên bản ngắn gọn của kích thước khu vực. Nếu bạn thêm kích thước của 3 vùng đó lên 102 MB, bạn phải ở mức gần 1 GB.

Vậy có gì trong đó? Vâng, bạn có thể xem bằng cách sử dụng dq. Bởi spelunking bạn có thể tìm thấy một gợi ý tại sao chúng được phân bổ. Có lẽ mã được quản lý của bạn gọi một số mã của bên thứ ba có mã gốc.

Bạn có thể tìm thấy các tham chiếu đến heap của mình bằng cách sử dụng !heap 6fff0000 -x -v. Nếu có tài liệu tham khảo, bạn có thể xem những vùng bộ nhớ mà họ đang sống bằng cách sử dụng lại! Trong vấn đề khách hàng của tôi, tôi tìm thấy một tham chiếu đã sống trên một khu vực có "Cách sử dụng: Ngăn xếp". Gợi ý "Thông tin thêm:" đã tham chiếu chuỗi của ngăn xếp đã xảy ra có một số lệnh gọi/sao chép basic_string lớn ở trên cùng.

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