2008-09-02 62 views
120

Làm thế nào để bạn tìm thấy rò rỉ bộ nhớ trong Java (sử dụng, ví dụ, JHat)? Tôi đã cố gắng để tải đống đổ lên trong JHat để có một cái nhìn cơ bản. Tuy nhiên, tôi không hiểu làm thế nào tôi có nghĩa vụ để có thể tìm thấy các tài liệu tham khảo gốc (ref) hoặc bất cứ điều gì nó được gọi là. Về cơ bản, tôi có thể nói rằng có vài trăm megabyte các mục bảng băm ([java.util.HashMap $ Entry hoặc một cái gì đó như thế), nhưng bản đồ được sử dụng khắp nơi ... Có cách nào để tìm kiếm các bản đồ lớn không , hoặc có thể tìm thấy rễ chung của cây đối tượng lớn?Cách tìm rò rỉ bộ nhớ Java

[Chỉnh sửa] Ok, tôi đã đọc câu trả lời cho đến nay nhưng hãy chỉ nói tôi là một tên khốn rẻ tiền (có nghĩa là tôi quan tâm nhiều hơn đến việc học cách sử dụng JHat hơn là trả tiền cho JProfiler). Ngoài ra, JHat luôn luôn có sẵn vì nó là một phần của JDK. Trừ khi tất nhiên không có cách nào với JHat nhưng sức mạnh vũ phu, nhưng tôi không thể tin rằng đó có thể là trường hợp.

Ngoài ra, tôi không nghĩ rằng tôi có thể thực sự sửa đổi (thêm ghi nhật ký tất cả kích thước bản đồ) và chạy nó đủ lâu để tôi nhận thấy sự rò rỉ.

+0

Oracle có một trang liên quan ở đây: https: //docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html#BABIIIAC – Laurel

+0

Đây là một "phiếu bầu" khác cho JProfiler. Nó hoạt động khá tốt để phân tích heap, có giao diện người dùng tốt và hoạt động khá tốt. Như McKenzieG1 nói, 500 đô la rẻ hơn số lượng thời gian bạn có thể đốt cháy để tìm nguồn gốc cho những rò rỉ này. Theo như giá của các công cụ đi, nó không phải là xấu. – joev

Trả lời

115

Tôi sử dụng cách tiếp cận sau để tìm rò rỉ bộ nhớ trong Java. Tôi đã sử dụng jProfiler với thành công lớn, nhưng tôi tin rằng bất kỳ công cụ chuyên dụng nào có khả năng vẽ đồ thị (diffs được dễ dàng hơn để phân tích dưới dạng đồ họa) sẽ hoạt động.

  1. Khởi động ứng dụng và chờ cho đến khi trạng thái "ổn định", khi tất cả quá trình khởi tạo hoàn tất và ứng dụng không hoạt động.
  2. Chạy hoạt động bị nghi ngờ là bị rò rỉ bộ nhớ nhiều lần để cho phép bất kỳ bộ nhớ cache nào, khởi tạo liên quan đến DB diễn ra.
  3. Chạy GC và chụp nhanh bộ nhớ.
  4. Chạy lại thao tác. Tùy thuộc vào độ phức tạp của hoạt động và kích thước của dữ liệu được xử lý hoạt động có thể cần phải chạy nhiều lần.
  5. Chạy GC và chụp nhanh bộ nhớ.
  6. Chạy khác biệt cho 2 ảnh chụp nhanh và phân tích.

Phân tích cơ bản nên bắt đầu từ những khác biệt tích cực nhất, ví dụ, loại đối tượng và tìm nguyên nhân khiến các đối tượng phụ đó dính vào bộ nhớ.

Đối với các ứng dụng web xử lý các yêu cầu trong phân tích chuỗi chủ đề phức tạp hơn, nhưng phương pháp tiếp cận chung vẫn được áp dụng.

Tôi đã thực hiện khá nhiều dự án nhằm giảm thiểu dung lượng bộ nhớ của ứng dụng và cách tiếp cận chung này với một số chỉnh sửa và mẹo cụ thể của ứng dụng luôn hoạt động tốt.

+4

Bạn có thể cho tôi biết cách chạy GC theo cách thủ công –

+7

Hầu hết (nếu không phải tất cả) trình bày Java cung cấp cho bạn một tùy chọn để gọi GC bằng một cú nhấp chuột. Hoặc bạn có thể gọi System.gc() từ vị trí thích hợp trong mã của bạn. –

+3

Ngay cả khi chúng tôi gọi là Hệ thống.gc() JVM có thể chọn bỏ qua cuộc gọi. AFAIK này là JVM cụ thể. +1 cho câu trả lời. –

4

Vâng, luôn có giải pháp công nghệ thấp để thêm ghi nhật ký kích thước bản đồ của bạn khi bạn sửa đổi bản đồ, sau đó tìm kiếm nhật ký mà bản đồ đang phát triển vượt quá kích thước hợp lý.

0

Bạn thực sự cần sử dụng trình thu thập bộ nhớ theo dõi phân bổ. Hãy xem JProfiler - tính năng "heap walker" của chúng rất tuyệt và chúng có tích hợp với tất cả các IDE Java chính. Nó không phải là miễn phí, nhưng nó không phải là đắt tiền hoặc ($ 499 cho một giấy phép duy nhất) - bạn sẽ đốt cháy 500 $ giá trị của thời gian khá nhanh chóng đấu tranh để tìm một rò rỉ với các công cụ ít phức tạp.

5

Có các công cụ sẽ giúp bạn tìm thấy sự rò rỉ của bạn, như điều khiển nhiệm vụ JProbe, YourKit, AD4J hoặc JRockit. Người cuối cùng là cá nhân tôi biết rõ nhất. Bất kỳ công cụ tốt nào đều cho phép bạn đi sâu vào một mức mà bạn có thể dễ dàng xác định những rò rỉ và nơi các đối tượng bị rò rỉ được phân bổ.

Sử dụng HashTables, Hashmaps hoặc tương tự là một trong số ít cách để bạn có thể rò rỉ một cách tình cờ bộ nhớ trong Java. Nếu tôi phải tìm rò rỉ bằng tay, tôi sẽ in kích thước bằng chữ in hoa cương của tôi, và từ đó tìm thấy nơi tôi thêm các mục và quên xóa chúng.

0

NetBeans có trình tạo hồ sơ tích hợp.

12

Công cụ là một trợ giúp lớn.

Tuy nhiên, có những lúc bạn không thể sử dụng công cụ: khối đống quá lớn khiến công cụ bị hỏng, bạn đang cố gỡ rối máy trong một số môi trường sản xuất mà bạn chỉ có quyền truy cập trình bao, v.v.

Trong trường hợp đó, nó giúp biết cách của bạn xung quanh tệp kết xuất hprof.

Tìm SITES BEGIN. Điều này cho bạn thấy những đối tượng nào đang sử dụng nhiều bộ nhớ nhất. Nhưng các đối tượng không được gộp chung với nhau theo loại: mỗi mục cũng bao gồm một "dấu vết" ID. Sau đó, bạn có thể tìm kiếm "TRACE nnnn" để xem vài khung hình đầu tiên của ngăn xếp nơi đối tượng được phân bổ. Thông thường, một khi tôi nhìn thấy nơi mà đối tượng được phân bổ, tôi tìm thấy một lỗi và tôi đã hoàn tất. Ngoài ra, lưu ý rằng bạn có thể kiểm soát số lượng khung được ghi trong ngăn xếp với các tùy chọn để -Xrunhprof.

Nếu bạn kiểm tra trang web phân bổ và không thấy bất kỳ điều gì sai, bạn phải bắt đầu chuỗi ngược từ một số đối tượng trực tiếp đó thành đối tượng gốc để tìm chuỗi tham chiếu bất ngờ. Đây là nơi mà một công cụ thực sự hữu ích, nhưng bạn có thể làm điều tương tự bằng tay (tốt, với grep). Không chỉ có một đối tượng gốc (tức là, đối tượng không bị thu gom rác).Các chủ đề, các lớp và các khung ngăn xếp hoạt động như các đối tượng gốc và bất kỳ thứ gì mà chúng tham chiếu mạnh mẽ đều không thể thu thập được.

Để thực hiện chuỗi, hãy xem phần DAP HEAP cho các mục có id dấu vết không hợp lệ. Điều này sẽ đưa bạn đến một mục nhập OBJ hoặc ARR, trong đó cho thấy một định danh đối tượng duy nhất trong hệ thập lục phân. Tìm kiếm tất cả các lần xuất hiện của id đó để tìm ai có tham chiếu mạnh mẽ đối tượng. Thực hiện theo từng đường dẫn ngược lại khi chúng rẽ nhánh cho đến khi bạn tìm ra nơi rò rỉ. Xem lý do tại sao một công cụ tiện dụng như vậy?

Thành viên tĩnh là người phạm tội lặp lại vì rò rỉ bộ nhớ. Trong thực tế, ngay cả khi không có một công cụ, nó sẽ có giá trị chi tiêu một vài phút xem xét mã của bạn cho các thành viên Map tĩnh. Bản đồ có thể lớn lên không? Có bất cứ điều gì bao giờ làm sạch các mục của nó?

+0

"đống đống là rất lớn nó treo công cụ" - tôi đã kiểm tra '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' trên bộ nhớ lớn (ví dụ: 'OutOfMemoryError' , từ các ứng dụng cần phân tích đống nhất!). NetBeans Profiler dường như sử dụng một thuật toán khác để lập chỉ mục các tham chiếu có thể nhận _slow_ trên các bãi chứa lớn nhưng ít nhất không tiêu thụ bộ nhớ không bị chặn trong công cụ và sự cố. –

-1

bạn có thể muốn xem jconsole. Nó cũng là một phần của JDK và tôi đã tìm thấy nó hữu ích để tìm rò rỉ bộ nhớ/tham chiếu kết hợp với jhat. Ngoài ra, hãy xem mục nhập blog this.

46

Người hỏi ở đây, tôi phải nói rằng việc nhận một công cụ không mất 5 phút để trả lời bất kỳ nhấp chuột nào giúp bạn dễ dàng tìm thấy rò rỉ bộ nhớ tiềm ẩn hơn.

Vì mọi người đang đề xuất một số công cụ (tôi chỉ thử hình ảnh từ khi tôi nhận được điều đó trong thử nghiệm JDK và JProbe) mặc dù tôi nên đề xuất một công cụ mã nguồn mở/miễn phí được xây dựng trên nền tảng Eclipse, Bộ phân tích bộ nhớ (đôi khi được tham chiếu) là bộ phân tích bộ nhớ SAP) có sẵn trên http://www.eclipse.org/mat/. Điều thực sự thú vị về công cụ này là nó đã lập chỉ mục vùng heap khi tôi mở nó lần đầu tiên cho phép nó hiển thị dữ liệu như heap được giữ lại mà không cần chờ 5 phút cho mỗi đối tượng. công cụ tôi đã thử).

Khi bạn mở bãi chứa, màn hình đầu tiên hiển thị cho bạn biểu đồ hình tròn với các đối tượng lớn nhất (đếm đống được giữ lại) và có thể nhanh chóng điều hướng xuống các đối tượng lớn để thoải mái. Nó cũng có một khả năng phát hiện có khả năng bị rò rỉ mà tôi reccon có thể có ích, nhưng kể từ khi chuyển hướng là đủ cho tôi, tôi đã không thực sự nhận được vào nó.

+0

Lưu ý đáng giá: dường như trong Java 5 trở lên, tham số VM 'HeapDumpOnCtrlBreak' * không khả dụng *. Các giải pháp tôi đã tìm thấy (cho đến nay, vẫn đang tìm kiếm) là sử dụng JMap để đổ tập tin '.hprof', mà sau đó tôi đưa vào Eclipse và sử dụng MAT để kiểm tra. – Ben

+1

Về việc thu thập kết xuất đống, hầu hết các trình lược tả (bao gồm JVisualVM) bao gồm tùy chọn để kết xuất cả đống và luồng vào một tệp. – bbaja42

3

Hầu hết thời gian, trong các ứng dụng doanh nghiệp, vùng heap Java được cung cấp lớn hơn kích thước tối đa lý tưởng từ 12 đến 16 GB. Tôi đã tìm thấy nó khó khăn để làm cho hồ sơ NetBeans làm việc trực tiếp trên các ứng dụng java lớn.

Nhưng thường thì điều này là không cần thiết. Bạn có thể sử dụng tiện ích jmap đi kèm với jdk để lấy một đống "sống", đó là jmap sẽ đổ đống sau khi chạy GC. Thực hiện một số thao tác trên ứng dụng, đợi cho đến khi thao tác hoàn tất, sau đó lấy một vùng lưu trữ "live" khác. Sử dụng các công cụ như Eclipse MAT để tải heapdumps, sắp xếp trên biểu đồ, xem các đối tượng nào đã tăng lên, hoặc cái nào là cao nhất, Điều này sẽ đưa ra một đầu mối.

su proceeuser 
/bin/jmap -dump:live,format=b,file=/tmp/2930javaheap.hrpof 2930(pid of process) 

Chỉ có một vấn đề với cách tiếp cận này; Các đống đống lớn, ngay cả với tùy chọn trực tiếp, có thể quá lớn để chuyển sang vòng phát triển và có thể cần một máy có đủ bộ nhớ/RAM để mở.

Đó là nơi biểu đồ lớp đưa vào hình ảnh. Bạn có thể đổ một biểu đồ lớp học trực tiếp bằng công cụ jmap. Điều này sẽ chỉ cung cấp biểu đồ lớp về cách sử dụng bộ nhớ. Về cơ bản, nó sẽ không có thông tin để tham chiếu chuỗi. Ví dụ, nó có thể đặt mảng char ở trên cùng. Và lớp String ở đâu đó bên dưới. Bạn phải tự mình vẽ kết nối.

jdk/jdk1.6.0_38/bin/jmap -histo:live 60030 > /tmp/60030istolive1330.txt 

Thay vì sử dụng hai khối đống, lấy hai biểu đồ lớp, như mô tả ở trên; Sau đó so sánh các biểu đồ lớp và xem các lớp đang tăng lên. Xem bạn có thể liên kết các lớp Java với các lớp ứng dụng của bạn không. Điều này sẽ cho một gợi ý khá tốt. Đây là một kịch bản pythons có thể giúp bạn so sánh hai bãi biểu đồ jmap. histogramparser.py

Cuối cùng các công cụ như JConolse và VisualVm là điều cần thiết để xem sự tăng trưởng bộ nhớ theo thời gian và xem liệu có rò rỉ bộ nhớ hay không. Cuối cùng đôi khi vấn đề của bạn có thể không phải là rò rỉ bộ nhớ, nhưng sử dụng bộ nhớ cao.Để cho phép ghi nhật ký GC, hãy sử dụng GC nén nâng cao và mới hơn như G1GC; và bạn có thể sử dụng công cụ jdk như jstat để xem hành vi GC sống

jstat -gccause pid <optional time interval> 

referecences khác để google cho -jhat, jmap, Full GC, phân bổ Humongous, G1GC

+0

đã thêm một bài đăng trên blog có thêm chi tiết tại đây - http://alexpunnen.blogspot.in/2015/06/long-running-java-process-resource.html –