Kích thước đống rất lớn của Java [đã đóng]


76

Có ai có kinh nghiệm sử dụng heap rất lớn, 12 GB hoặc cao hơn trong Java không?

  • GC có làm cho chương trình không sử dụng được không?
  • Bạn sử dụng thông số GC nào?
  • JVM, Sun hay BEA sẽ phù hợp hơn cho việc này?
  • Nền tảng nào, Linux hay Windows, hoạt động tốt hơn trong những điều kiện như vậy?
  • Trong trường hợp của Windows, có sự khác biệt nào về hiệu suất giữa Vista và XP 64 bit khi tải bộ nhớ cao như vậy không?

Câu trả lời:


74

Nếu ứng dụng của bạn không tương tác và GC tạm dừng không phải là vấn đề đối với bạn, thì sẽ không có vấn đề gì đối với Java 64-bit để xử lý các đống rất lớn, ngay cả trong hàng trăm GB. Chúng tôi cũng không nhận thấy bất kỳ vấn đề ổn định nào trên Windows hoặc Linux.

Tuy nhiên, khi bạn cần giữ GC tạm dừng ở mức thấp, mọi thứ trở nên thực sự tồi tệ:

  1. Quên thông lượng mặc định, dừng GC thế giới. Nó sẽ tạm dừng ứng dụng của bạn trong vài chục giây đối với những đống vừa phải (<~ 30 GB) và vài phút đối với những tệp lớn (> ~ 30 GB). Và việc mua DIMM nhanh hơn sẽ không giúp được gì.

  2. Đặt cược tốt nhất có lẽ là bộ sưu tập CMS, được kích hoạt bởi -XX: + UseConcMarkSweepGC. Trình thu gom rác CMS chỉ dừng ứng dụng cho giai đoạn đánh dấu ban đầu và giai đoạn nhận xét. Đối với những đống rất nhỏ như <4 GB, điều này thường không phải là vấn đề, nhưng đối với một ứng dụng tạo ra nhiều rác và một đống lớn, giai đoạn nhận lại có thể mất khá nhiều thời gian - thường ít hơn nhiều sau đó hoàn toàn dừng , nhưng vẫn có thể là một vấn đề đối với các đống rất lớn.

  3. Khi bộ thu gom rác CMS không đủ nhanh để hoàn thành hoạt động trước khi thế hệ có hạn sử dụng đầy, nó sẽ trở lại trạng thái dừng tiêu chuẩn GC. Mong đợi khoảng thời gian tạm dừng dài khoảng 30 giây trở lên cho các đống có kích thước 16 GB. Bạn có thể cố gắng tránh điều này bằng cách giữ cho tỷ lệ sản xuất rác tồn tại lâu dài của ứng dụng của bạn càng thấp càng tốt. Lưu ý rằng số lượng lõi chạy ứng dụng của bạn càng cao thì vấn đề này càng lớn, vì CMS chỉ sử dụng một lõi. Rõ ràng, hãy cẩn thận không có đảm bảo CMS không rơi trở lại bộ thu STW. Và khi nó xảy ra, nó thường xảy ra ở mức tải cao nhất và ứng dụng của bạn sẽ chết trong vài giây. Có thể bạn sẽ không muốn ký SLA cho một cấu hình như vậy.

  4. Chà, có điều G1 mới đó. Về mặt lý thuyết, nó được thiết kế để tránh các vấn đề với CMS, nhưng chúng tôi đã thử nó và nhận thấy rằng:

    • Thông lượng của nó kém hơn so với CMS.
    • Về mặt lý thuyết, nó nên tránh thu thập các khối bộ nhớ phổ biến trước, tuy nhiên nó sẽ sớm đạt đến trạng thái mà hầu như tất cả các khối đều "phổ biến" và các giả định mà nó dựa trên chỉ đơn giản là ngừng hoạt động.
    • Cuối cùng, dự phòng điểm dừng của thế giới vẫn tồn tại đối với G1; hỏi Oracle, khi mã đó được cho là sẽ được chạy. Nếu họ nói "không bao giờ", hãy hỏi họ, tại sao mã ở đó. Vì vậy, IMHO G1 thực sự không làm cho vấn đề đống lớn của Java biến mất, nó chỉ làm cho nó (được cho là) ​​nhỏ hơn một chút.
  5. Nếu bạn bỏ ra một khoản tiền lớn cho một máy chủ lớn với bộ nhớ lớn, bạn cũng có thể mua một phần cứng thương mại tốt, công nghệ GC không tạm dừng, như công nghệ được cung cấp bởi Azul. Chúng tôi có một trong những máy chủ của họ với RAM 384 GB và nó thực sự hoạt động tốt - không có tạm dừng, 0 dòng mã dừng trên thế giới trong GC.

  6. Viết phần chết tiệt của ứng dụng của bạn đòi hỏi nhiều bộ nhớ trong C ++, giống như LinkedIn đã làm với xử lý đồ thị xã hội. Bạn vẫn sẽ không tránh được tất cả các vấn đề bằng cách làm điều này (ví dụ như phân mảnh đống), nhưng chắc chắn sẽ dễ dàng hơn để giữ mức tạm dừng ở mức thấp.


1
5. Không có khả năng. Máy 192MB khoảng EUR15K. Định giá Azul là doanh nghiệp, phải không?
Stephan Eggermont

1
Đây dễ dàng là bản tóm tắt tốt nhất ở đây. Tôi muốn thêm hai điều: (1) CMSInitiatingOccupancyFraction có thể giảm thiểu vấn đề "CMS không thể hoàn thành trước khi thế hệ cũ lấp đầy", nhưng (2) không giống như bộ thu thập thông lượng, CMS không thu gọn heap nên việc phân mảnh thường sẽ buộc STW GC cuối cùng.
jbellis

@StephanEggermont ý bạn là máy 192 GB phải không?
om-nom-nom

@ om-nom-nom vâng, đúng vậy. Không thể chỉnh sửa bình luận của một ngày sau đó, không may
Stephan Eggermont

17

Tôi là Giám đốc điều hành của Azul Systems nên rõ ràng tôi có thành kiến ​​về quan điểm của mình về chủ đề này! :) Điều đó đang được nói ...

CTO của Azul, Gil Tene, có cái nhìn tổng quan tốt đẹp về các vấn đề liên quan đến Thu gom rác và đánh giá các giải pháp khác nhau trong phần trình bày Hiểu biết về Thu gom rác trong Java và Những gì bạn có thể làm với nó , và có thêm chi tiết trong bài viết này: http: // www.infoq.com/articles/azul_gc_in_detail .

Azul's C4 Garbage Collector trong Zing JVM của chúng tôi vừa song song vừa đồng thời và sử dụng cùng một cơ chế GC cho cả thế hệ mới và cũ, hoạt động đồng thời và thu gọn trong cả hai trường hợp. Quan trọng nhất, C4 không có điểm dừng của thế giới. Tất cả quá trình nén được thực hiện đồng thời với ứng dụng đang chạy. Chúng tôi có những khách hàng đang chạy rất lớn (hàng trăm GByte) với trường hợp xấu hơn thời gian tạm dừng GC là <10 msec và tùy thuộc vào ứng dụng, thời gian thường ít hơn 1-2 msec.

Vấn đề với CMS và G1 là tại một thời điểm nào đó bộ nhớ heap của Java phải được nén lại, và cả hai trình thu gom rác đó đều dừng-the-world / STW (tức là tạm dừng ứng dụng) để thực hiện nén. Vì vậy, trong khi CMS và G1 có thể loại bỏ các tạm dừng STW, chúng không loại bỏ chúng. Tuy nhiên, C4 của Azul loại bỏ hoàn toàn các lệnh tạm dừng STW và đó là lý do tại sao Zing có mức tạm dừng GC thấp như vậy ngay cả đối với các kích thước heap khổng lồ.


29
Sau khoảng 6 email qua lại với một trong những người bán hàng của bạn, tôi đã từ bỏ việc lấy thông tin giá cả. Một giải pháp bạn thậm chí không thể đánh giá không phải là một giải pháp.
Chad Wilson

14

Chúng tôi có một ứng dụng mà chúng tôi phân bổ 12-16 Gb nhưng nó thực sự chỉ đạt 8-10 trong hoạt động bình thường. Chúng tôi sử dụng Sun JVM (đã thử dùng IBM và đó là một thảm họa nhưng đó có thể là sự thiếu hiểu biết từ phía chúng tôi ... Tôi có những người bạn thề với nó - đó là công việc ở IBM). Miễn là bạn cung cấp cho ứng dụng của mình khoảng trống, JVM có thể xử lý các kích thước đống lớn với không quá nhiều GC. Rất nhiều bộ nhớ 'bổ sung' là chìa khóa.
Linux hầu như luôn ổn định hơn Windows và khi nó không ổn định thì việc tìm ra lý do sẽ dễ dàng hơn rất nhiều. Solaris cũng rất vững chắc và bạn cũng có DTrace :) Với những tải trọng như thế này, tại sao bạn lại sử dụng Vista hoặc XP? Bạn chỉ đang yêu cầu rắc rối. Chúng tôi không làm bất cứ điều gì lạ mắt với các thông số GC. Chúng tôi đặt mức phân bổ tối thiểu bằng với mức tối đa nên không phải liên tục cố gắng thay đổi kích thước nhưng chỉ có vậy.


2
Tôi sẽ không nói rằng Linux ổn định hơn so với Windows, tuy nhiên rất có thể Sun test nó JVM nhiều hơn trên đơn vị và linex sau đó nó làm trên windows.
Ian Ringrose

9

Tôi đã sử dụng hơn 60 GB kích thước heap trên hai ứng dụng khác nhau trong Linux và Solaris tương ứng bằng cách sử dụng phiên bản 64-bit (rõ ràng là) của Sun 1.6 JVM.

Tôi chưa bao giờ gặp sự cố thu gom rác với ứng dụng dựa trên Linux ngoại trừ khi đẩy lên gần giới hạn kích thước đống. Để tránh các vấn đề liên quan đến kịch bản đó (quá nhiều thời gian dành cho việc thu gom rác), tôi chỉ cần tối ưu hóa việc sử dụng bộ nhớ trong suốt chương trình để mức sử dụng cao nhất thấp hơn khoảng 5-10% giới hạn kích thước heap 64 GB.

Tuy nhiên, với một ứng dụng khác đang chạy dưới Solaris, tôi đã gặp phải các vấn đề nghiêm trọng về thu thập rác khiến cần phải thực hiện rất nhiều điều chỉnh. Điều này chủ yếu bao gồm ba bước:

  1. Bật / buộc sử dụng bộ thu gom rác song song thông qua -XX: + UseParallelGC -XX: + Tùy chọn UseParallelOldGC JVM, cũng như kiểm soát số lượng luồng GC được sử dụng thông qua tùy chọn -XX: ParallelGCThreads. Xem " Điều chỉnh thu thập rác máy ảo Java SE 6 HotSpot " để biết thêm chi tiết.

  2. Cài đặt rộng rãi và có vẻ vô lý của các biến cục bộ thành "null" sau khi chúng không còn cần thiết nữa. Hầu hết trong số này là các biến đáng lẽ đủ điều kiện để thu gom rác sau khi vượt ra khỏi phạm vi, và chúng không phải là tình huống rò rỉ bộ nhớ vì các tham chiếu không được sao chép. Tuy nhiên, chiến lược "cầm tay" này để hỗ trợ thu gom rác là cần thiết không thể giải thích được vì một số lý do cho ứng dụng này trong nền tảng Solaris đang được đề cập.

  3. Sử dụng có chọn lọc lời gọi phương thức System.gc () trong các phần mã khóa sau các khoảng thời gian dài phân bổ đối tượng tạm thời. Tôi biết các cảnh báo tiêu chuẩn chống lại việc sử dụng các lệnh gọi này và lập luận rằng chúng thường không cần thiết, nhưng tôi thấy chúng rất quan trọng trong việc xử lý việc thu gom rác khi chạy ứng dụng sử dụng nhiều bộ nhớ này.

Ba bước trên làm cho nó khả thi để giữ cho ứng dụng này được chứa và chạy hiệu quả ở mức sử dụng heap khoảng 60 GB thay vì phát triển mất kiểm soát lên đến giới hạn kích thước heap 128 GB đã có. Đặc biệt, bộ thu gom rác song song rất hữu ích vì các chu kỳ thu gom rác chính rất tốn kém khi có nhiều đối tượng, tức là, thời gian cần thiết để thu gom rác chính là một hàm của số lượng đối tượng trong đống.

Tôi không thể bình luận về các vấn đề cụ thể của nền tảng khác ở quy mô này, cũng như chưa sử dụng các JVM không phải của Sun (Oracle).


8

12Gb sẽ không có vấn đề gì với việc triển khai JVM tốt như Sun's Hotspot. Tôi khuyên bạn nên sử dụng đồng thời Mark và Sweep colllector (-XX: + UseConcMarkSweepGC) khi sử dụng SUN VM.

Hệ điều hành không nên tạo ra sự khác biệt lớn đối với hiệu suất GC.

Tất nhiên, bạn sẽ cần một hệ điều hành 64 bit và một máy có đủ RAM vật lý.


7

Tôi cũng khuyên bạn nên cân nhắc thực hiện kết xuất đống và xem nơi có thể cải thiện việc sử dụng bộ nhớ trong ứng dụng của bạn và phân tích kết xuất trong một cái gì đó chẳng hạn như MAT của Eclipse . Có một số bài báo trên trang MAT về việc bắt đầu tìm kiếm rò rỉ bộ nhớ. Bạn có thể sử dụng jmap để lấy kết xuất với một cái gì đó chẳng hạn như ...

jmap -heap:format=b pid

... và điều này trả lời câu hỏi thực tế như thế nào?
ddimitrov 18/10/08

3
bởi vì với kích thước heap lớn như vậy, bạn nên tìm cách giảm dung lượng bộ nhớ cũng như tối ưu hóa JVM
jlintz

Đồng ý. Trừ khi bạn có một loại ứng dụng rất đặc biệt, bạn không cần 12GB heap. Điều đó thường chỉ ra các phương pháp mã hóa không tốt, chẳng hạn như tải những thứ lớn vào RAM ngay lập tức mà bạn nên phát trực tiếp. Làm điều đó đúng và ứng dụng của bạn cũng mở rộng. Làm sai và bạn sẽ phải tiếp tục tăng kích thước heap của mình khi ứng dụng của bạn bận rộn hơn / xử lý khối lượng dữ liệu lớn hơn.
Frans

2

Như đã đề cập ở trên, nếu bạn có một chương trình không tương tác, bộ thu gom rác (GC) mặc định sẽ hoạt động tốt. Nếu bạn có một chương trình tương tác và bạn (1) không cấp phát bộ nhớ nhanh hơn mức GC có thể theo kịp và (2) không tạo các đối tượng tạm thời (hoặc tập hợp các đối tượng) quá lớn (so với tổng bộ nhớ JVM tối đa) để GC hoạt động xung quanh, thì CMS là dành cho bạn.

Bạn sẽ gặp rắc rối nếu bạn có một chương trình tương tác mà GC không có đủ chỗ thở. Điều đó đúng bất kể bạn có bao nhiêu bộ nhớ, nhưng bạn càng có nhiều bộ nhớ, nó càng trở nên tồi tệ. Đó là bởi vì khi bạn sắp hết bộ nhớ, CMS sẽ hết bộ nhớ, trong khi các GC nén (bao gồm cả G1) sẽ tạm dừng mọi thứ cho đến khi tất cả bộ nhớ đã được kiểm tra rác. Khoảng dừng giữa thế giới này càng lớn khi bạn có nhiều bộ nhớ. Tin tôi đi, bạn không muốn các servlet của mình tạm dừng hơn một phút. Tôi đã viết một câu trả lời StackOverflow chi tiết về những lần tạm dừng này trong G1.

Kể từ đó, công ty của tôi đã chuyển sang Azul Zing. Nó vẫn không thể xử lý trường hợp ứng dụng của bạn thực sự cần nhiều bộ nhớ hơn những gì bạn có, nhưng cho đến thời điểm đó, nó vẫn chạy như mơ.

Nhưng tất nhiên, Zing không miễn phí và nước sốt đặc biệt của nó đã được cấp bằng sáng chế. Nếu bạn có nhiều thời gian hơn tiền bạc, hãy thử viết lại ứng dụng của mình để sử dụng một nhóm JVM.

Về phía chân trời, Oracle đang làm việc trên một GC hiệu suất cao cho các heap nhiều gigabyte. Tuy nhiên, cho đến hôm nay đó không phải là một lựa chọn.


1

Nếu bạn chuyển sang 64-bit, bạn sẽ sử dụng nhiều bộ nhớ hơn. Con trỏ trở thành 8 byte thay vì 4. Nếu bạn đang tạo nhiều đối tượng, điều này có thể nhận thấy vì mọi đối tượng đều là một tham chiếu (con trỏ).

Gần đây tôi đã cấp phát 15GB bộ nhớ trong Java bằng Sun 1.6 JVM mà không gặp vấn đề gì. Mặc dù tất cả chỉ được cấp phát một lần. Không có nhiều bộ nhớ hơn được cấp phát hoặc giải phóng sau số lượng ban đầu. Đây là trên Linux nhưng tôi tưởng tượng Sun JVM sẽ hoạt động tốt trên Windows 64-bit.


1

Bạn nên thử chạy visualgc trên ứng dụng của mình. Đây là một công cụ trực quan hóa đống, là một phần của tải xuống jvmstat tại http://java.sun.com/performance/jvmstat/

Nó dễ dàng hơn rất nhiều so với đọc nhật ký GC.

Nó nhanh chóng giúp bạn hiểu cách các phần (thế hệ) của heap đang hoạt động. Trong khi tổng số heap của bạn có thể là 10GB, các phần khác nhau của heap sẽ nhỏ hơn nhiều. GC trong phần Eden của heap tương đối rẻ, trong khi các GC đầy đủ ở thế hệ cũ thì đắt. Định kích thước đống của bạn sao cho Eden rộng lớn và thế hệ cũ hầu như không bao giờ bị đụng đến là một chiến lược tốt. Điều này có thể dẫn đến một đống tổng thể rất lớn, nhưng cái quái gì vậy, nếu JVM không bao giờ chạm vào trang, nó chỉ là một trang ảo và không cần phải chiếm RAM.


1

Một vài năm trước, tôi đã so sánh JRockit và Sun JVM cho một đống 12G. JRockit đã thắng và sự hỗ trợ của các trang khổng lồ trên Linux đã giúp thử nghiệm của chúng tôi chạy nhanh hơn 20%. YMMV trong bài kiểm tra của chúng tôi rất tốn bộ xử lý / bộ nhớ và chủ yếu là đơn luồng.


Đó là phiên bản Java nào, và hôm nay bạn có thời gian để làm lại không? Các con số sẽ rất giao nhau.
Thorbjørn Ravn Andersen

Tôi không còn tư vấn cho cùng một công ty nữa, vì vậy tôi thậm chí không có môi trường để thử việc này. Đó là JRockit JDK1.5, IIRC.
ShabbyDoo

1

đây là một bài viết trên gc TỪ một trong những nhà vô địch Java - http://kirk.blog-city.com/is_your_concurrent_collector_failing_you.htm

Kirk, tác giả viết "Gửi cho tôi nhật ký GC của bạn

Tôi hiện đang quan tâm đến việc nghiên cứu nhật ký GC do Sun JVM sản xuất. Vì những nhật ký này không chứa thông tin liên quan đến kinh doanh nên sẽ giảm bớt mối lo ngại về việc bảo vệ thông tin quan trọng. Tất cả những gì tôi yêu cầu với nhật ký mà bạn đề cập đến Hệ điều hành, thông tin phiên bản đầy đủ cho JRE và bất kỳ công tắc dòng lệnh liên quan đến heap / gc nào mà bạn đã đặt. Tôi cũng muốn biết liệu bạn có đang chạy Grails / Groovey, JRuby, Scala hay thứ gì khác ngoài hoặc cùng với Java hay không. Cài đặt tốt nhất là -Xloggc:. Xin lưu ý rằng nhật ký này không chuyển sang khi đạt đến giới hạn kích thước hệ điều hành của bạn. Nếu tôi thấy bất cứ điều gì thú vị, tôi sẽ sẵn lòng cung cấp cho bạn một bản tóm tắt rất nhanh để đáp lại. "




0

Bộ nhớ tối đa mà XP có thể giải quyết là 4 gig ( ở đây ). Vì vậy, bạn có thể không muốn sử dụng XP cho việc đó (sử dụng hệ điều hành 64 bit).


Hoặc sử dụng phiên bản XP 64 bit. ;)
Tyler Millican 18/10/08

Đây không phải là hạn chế của XP, mà là hạn chế của bất kỳ hệ điều hành 32-bit nào không sử dụng PAE.
TM.

1
Đó là một hạn chế của tất cả các hệ điều hành 32-bit, ngay cả những hệ điều hành sử dụng PAE.
James

@james, Nếu bạn đang sử dụng PAE, bạn sẽ thấy toàn bộ 4GB, nếu bạn không có PAE, thì bạn sẽ không thấy các thiết bị được ánh xạ vào bộ nhớ (cạc đồ họa, v.v.).
Milhous

0

mặt trời đã có một itanium 64-bit jvm trong một thời gian mặc dù itanium không phải là một điểm đến phổ biến. Các JVM 64-bit solaris và linux sẽ là thứ bạn nên theo đuổi.
Vài câu hỏi

1) ứng dụng của bạn có ổn định không?
2) bạn đã thử nghiệm ứng dụng trong JVM 32 bit chưa?
3) có thể chạy nhiều JVM trên cùng một hộp không?

Tôi hy vọng hệ điều hành 64-bit từ windows sẽ ổn định trong khoảng một năm hoặc lâu hơn nhưng cho đến lúc đó, solaris / linux có thể tốt hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.