2009-03-25 35 views
14

Các chuyên gia và con của việc duy trì một nhóm các đối tượng thường xuyên sử dụng và lấy một từ hồ bơi thay vì tạo một cái mới. Một cái gì đó như chuỗi interning ngoại trừ việc nó sẽ có thể cho tất cả các đối tượng lớp.Object Pooling

Ví dụ: nó có thể được coi là tốt vì nó tiết kiệm thời gian gc và thời gian tạo đối tượng. Mặt khác, nó có thể là một nút cổ chai đồng bộ hóa nếu được sử dụng từ nhiều chủ đề, yêu cầu deallocation rõ ràng và giới thiệu khả năng rò rỉ bộ nhớ. Bằng cách buộc lên bộ nhớ có thể được khai hoang, nó đặt thêm áp lực lên bộ thu gom rác.

+0

Các ý kiến ​​có vẻ tiêu cực, nhưng tôi đang xem xét một cái gì đó tương tự. Tôi có một ứng dụng j2me tạo ra hàng nghìn đối tượng hộp giới hạn tiềm ẩn. Nếu tôi có thể tạo ra một hồ bơi của họ sau đó tôi sẽ cho GC một công việc dễ dàng hơn sau này. Tôi tự hỏi nếu điều này vẫn còn là một ý tưởng tồi trong thế giới hạn chế của điện thoại di động. – izb

+0

Chỉ có đối tượng đắt tiền trong hồ bơi (như kết nối cơ sở dữ liệu và như vậy). Định nghĩa "đắt tiền" phụ thuộc rất nhiều vào yêu cầu của bạn. –

Trả lời

18

Trừ khi đối tượng tốn kém để tạo, tôi sẽ không bận tâm.

Lợi ích:

  • đối tượng Ít tạo ra - nếu đối tượng sáng tạo là tốn kém, điều này có thể là đáng kể. (Ví dụ kinh điển có lẽ là kết nối cơ sở dữ liệu, trong đó "sáng tạo" bao gồm thực hiện kết nối mạng đến máy chủ, cung cấp chứng thực, vv)

Nhược điểm:

  • đang phức tạp hơn
  • tài nguyên chung = khóa; tiềm năng cổ chai
  • Vi phạm mong đợi GC của kiếp đối tượng (hầu hết các đối tượng sẽ được shortlived)

Bạn có một vấn đề thực tế mà bạn đang cố gắng để giải quyết, hoặc là này đầu cơ? Tôi sẽ không nghĩ về việc làm một cái gì đó như thế này, trừ khi bạn đã có điểm chuẩn/chạy hồ sơ cho thấy rằng có một vấn đề.

+0

Tôi thực sự quan tâm đến việc giảm bất kỳ sự tắc nghẽn nào bằng cách nói rằng bộ thu gom rác trên thế giới trong một ứng dụng thời gian thực nhạy cảm trong thời gian thực. – baskin

+0

Vâng, bạn có thể nhìn vào Java thời gian thực - tôi chưa bao giờ sử dụng nó bản thân mình, nhưng nó sẽ là giá trị kiểm tra. Hãy thử điều chỉnh GC - có rất nhiều tùy chọn ở đó. Tất nhiên nếu bạn có thể chắc chắn rằng mã của bạn không phân bổ * bất kỳ * đối tượng nào trong bit độ trễ nhạy cảm, điều đó thật tuyệt - nhưng khó. –

+0

Có, tôi đã xem xét java RTS nhưng không nghiêng về hướng sử dụng nó chủ yếu bởi vì nó không miễn phí. GC điều chỉnh cũng là một cái gì đó tôi đã cố gắng ra ngoài, đặc biệt là chơi xung quanh với CMS của gc. Nó chỉ là tôi không nhấn đúng kết hợp tham số tối ưu có thể. Cảm ơn tất cả sự giúp đỡ của bạn. – baskin

2

Tôi đồng ý với điểm của Jon Skeet, nếu bạn không có lý do cụ thể để tạo một nhóm đối tượng, tôi sẽ không bận tâm.

Có một số trường hợp khi một hồ bơi thực sự hữu ích/cần thiết. Nếu bạn có một nguồn tài nguyên đắt tiền để tạo, nhưng có thể được tái sử dụng (chẳng hạn như kết nối cơ sở dữ liệu), có thể có ý nghĩa khi sử dụng một nhóm. Ngoài ra, trong trường hợp kết nối cơ sở dữ liệu, một hồ bơi rất hữu ích để ngăn ứng dụng của bạn mở quá nhiều kết nối đồng thời vào cơ sở dữ liệu.

21

Luật tối ưu hóa đầu tiên: không làm điều đó. Luật thứ hai: không làm điều đó trừ khi bạn thực sự đã đo lường và biết thực tế là bạn cần tối ưu hóa và ở đâu.

Chỉ khi các đối tượng thực sự đắt tiền để tạo và nếu chúng thực sự có thể được sử dụng lại (bạn có thể đặt lại trạng thái chỉ với các hoạt động công khai thành thứ có thể được sử dụng lại).

Hai lợi ích bạn đề cập không thực sự đúng: phân bổ bộ nhớ trong java là miễn phí (chi phí gần 10 hướng dẫn cpu, không có gì). Vì vậy, giảm việc tạo ra các đối tượng chỉ giúp bạn tiết kiệm thời gian dành cho hàm tạo. Điều này có thể đạt được với các đối tượng thực sự nặng có thể được tái sử dụng (kết nối cơ sở dữ liệu, chủ đề) mà không thay đổi: bạn sử dụng lại kết nối cùng một kết nối, cùng một chuỗi.

Thời gian GC không giảm. Trong thực tế nó có thể tồi tệ hơn. Với việc di chuyển các thế hệ GC (Java là, hoặc lên đến 1.5) chi phí của một lần chạy GC được xác định bởi số lượng các đối tượng còn sống, không phải bởi bộ nhớ được giải phóng.Các đối tượng sống sẽ được chuyển đến một không gian khác trong bộ nhớ (đây là điều làm cho việc phân bổ bộ nhớ quá nhanh: bộ nhớ tự do tiếp giáp trong mỗi khối GC) vài lần trước khi được đánh dấu là và chuyển vào không gian bộ nhớ thế hệ cũ hơn.

Ngôn ngữ lập trình và hỗ trợ, như GC, được thiết kế để ghi nhớ cách sử dụng phổ biến. Nếu bạn tránh xa việc sử dụng phổ biến trong nhiều trường hợp, bạn có thể sẽ gặp khó khăn hơn khi đọc mã hiệu quả hơn.

+0

Tôi thực sự quan tâm đến việc giảm bất kỳ tắc nghẽn bằng cách nói stop-the-world thu gom rác trong một ứng dụng thời gian thực nhạy cảm thời gian thực. Những gì bạn nói mặc dù làm cho rất nhiều ý nghĩa và tôi đồng ý rằng điểm chuẩn là cần thiết để có một quyết định như vậy. – baskin

+2

Thời gian GC * có thể * bị giảm - nếu bằng cách sử dụng một hồ bơi, bạn có thể tránh bao giờ cần phải phân bổ các đối tượng, ví dụ, đó có thể là một chiến thắng đáng kể trong một ứng dụng độ trễ thấp. Đó là một nỗi đau thực sự để đảm bảo bạn không bao giờ phân bổ mặc dù ... –

+0

(Tôi đồng ý rằng nó cũng có thể dễ dàng làm cho thời gian GC tồi tệ hơn, btw.) –

5

Không.

Đây là suy nghĩ của năm 2001. Các đối tượng duy nhất "hồ bơi" mà vẫn còn giá trị bất cứ điều gì bây giờ một ngày là một singleton. Tôi chỉ sử dụng các singletons để giảm việc tạo đối tượng cho các mục đích lược tả (vì vậy tôi có thể thấy rõ hơn những gì đang tác động đến mã).

Bất cứ điều gì khác bạn chỉ là phân mảnh bộ nhớ không có mục đích tốt.

Tiếp tục và chạy cấu hình để tạo 1.000.000 đối tượng. Nó không đáng kể.

Old article here.

+1

Với thời gian khởi tạo sau khởi tạo là không đáng kể. –

9

Pooling sẽ có nghĩa là bạn thường không thể tạo đối tượng bất biến. Điều này dẫn đến việc sao chép defencive vì vậy bạn cuối cùng gió lên làm cho nhiều bản sao hơn bạn sẽ nếu bạn chỉ cần thực hiện một đối tượng bất biến mới.

Tính không thay đổi không phải lúc nào cũng mong muốn, nhưng thường xuyên hơn không bạn sẽ thấy rằng mọi thứ có thể bất biến. Làm cho chúng không thay đổi để bạn có thể tái sử dụng chúng trong một hồ bơi có lẽ không phải là một ý tưởng tuyệt vời.

Vì vậy, trừ khi bạn biết chắc chắn rằng đó không phải là vấn đề. Làm cho mã rõ ràng và dễ dàng để làm theo và tỷ lệ cược là nó sẽ đủ nhanh. Nếu nó không phải là sau đó thực tế là mã là rõ ràng và dễ làm theo sẽ làm cho nó dễ dàng hơn để tăng tốc độ nó lên (nói chung).

+1

+1 để biết nỗi đau của tôi. Tôi vừa giải quyết một lỗi tham nhũng dữ liệu nghiêm trọng bằng cách loại bỏ một nhóm đối tượng. Profiling trên Java 1.3 và 1.4 cho thấy các hồ bơi như là một chiến thắng lớn, trên 1,5 nó làm chậm mã xuống. – Darron

+0

Tùy thuộc vào nội dung bạn đang chia sẻ. –

5

Nó hoàn toàn phụ thuộc vào cách đắt đối tượng của bạn là để tạo, so với số lần bạn tạo chúng ... ví dụ, đối tượng mà chỉ là cấu trúc tôn vinh (ví dụ chỉ chứa một vài lĩnh vực, và không các phương thức khác ngoài các trình truy cập) có thể là một trường hợp sử dụng thực sự cho việc gộp nhóm.

Ví dụ thực tế về cuộc sống: Tôi cần trích xuất một cách lặp lại n mục được xếp hạng cao nhất (số nguyên) từ quá trình tạo ra số lượng lớn cặp số nguyên/xếp hạng. Tôi đã sử dụng một đối tượng "cặp" (một số nguyên, và một giá trị xếp hạng float) trong một hàng đợi ưu tiên có giới hạn. Tái sử dụng các cặp, so với làm rỗng hàng đợi, ném các cặp đi, và tái tạo chúng, mang lại hiệu suất cải thiện 20% ... chủ yếu trong phí GC, bởi vì các cặp không bao giờ cần phải được phân bổ lại trong toàn bộ vòng đời của JVM.

3

Bể đối tượng thường chỉ là ý tưởng tốt cho đối tượng đắt tiền như kết nối cơ sở dữ liệu. Lên đến Java 1.4.2, các nhóm đối tượng có thể cải thiện hiệu suất nhưng với các nhóm đối tượng Java 5.0 có nhiều khả năng gây hại hơn so với trợ giúp và các nhóm đối tượng thường bị loại bỏ để cải thiện hiệu suất (và đơn giản)