2015-09-29 38 views
13

Tôi đang đọc về tính năng trong bản cập nhật Java 8 cho String pc (more info) nhưng tôi không chắc chắn nếu điều này về cơ bản làm cho String.intern() lỗi thời.Java 8 String pc so với String.intern()

Tôi biết rằng tính năng JVM này cần trình thu gom rác G1, có thể không phải là tùy chọn cho nhiều người, nhưng giả sử người dùng đang sử dụng G1GC, là có bất kỳ sự khác biệt/lợi thế/bất lợi nào của việc tự động sao chép được thực hiện bởi JVM bằng tay phải intern dây của bạn (một cách rõ ràng là lợi thế của việc không phải gây ô nhiễm mã của bạn với các cuộc gọi đến intern())?

Điều này đặc biệt thú vị xem xét rằng Oracle có thể làm cho G1GC GC mặc định trong java 9

+3

[Video được đề xuất] (https://www.youtube.com/watch?v=YgGAUGC9ksk) - nhưng dù sao đi nữa, kết luận luôn giống nhau: Bạn. Nên. Không phải. Quan tâm. – fge

+0

xin lỗi, không nên quan tâm đến điều gì? về cái nào để sử dụng (có nghĩa là chúng tương đương) hoặc về tính năng mới (có nghĩa là nó không hữu ích) ?? – Hilikus

+2

Có nghĩa là: chỉ cần sử dụng lớp 'String' mà không có suy nghĩ thứ hai. – fge

Trả lời

6

Với tính năng này, nếu bạn có 1000 đối tượng String riêng biệt, tất cả với cùng một nội dung "abc", JVM có thể làm cho họ chia sẻ cùng char[] nội bộ. Tuy nhiên, bạn vẫn có 1000 đối tượng riêng biệt String.

Với intern(), bạn sẽ chỉ có một đối tượng String. Vì vậy, nếu tiết kiệm bộ nhớ là mối quan tâm của bạn, intern() sẽ tốt hơn. Nó sẽ tiết kiệm không gian, cũng như thời gian GC.

Tuy nhiên, hiệu suất của intern() không phải là tuyệt vời, lần cuối tôi nghe thấy. Bạn có thể tốt hơn bằng cách có bộ nhớ cache chuỗi của riêng bạn, thậm chí bằng cách sử dụng một ConcurrentHashMap ... nhưng bạn cần phải chuẩn nó để đảm bảo.

+0

bạn có biết về bất kỳ sự khác biệt nào khác không? – Hilikus

+3

Thực ra, hiệu suất với String.intern có thể so sánh được với việc gộp chuỗi thủ công. Mikhail Vorontsov đã làm một số tiêu chuẩn hiệu suất và cho thấy rằng với tham số StringTableSize thiết lập đủ cao cho một nguyên tố, rằng hiệu suất được so sánh với chuỗi thủ công gộp mình. [http://java-performance.info/string-intern-in-java-6-7-8/](http://java-performance.info/string-intern-in-java-6-7-8 /) –

2

tôi muốn giới thiệu một yếu tố quyết định liên quan đến các đối tượng mục tiêu:

  • Đối với một nhà tích hợp hệ thống có một hệ thống gồm nhiều thư viện/khuôn khổ khác nhau, với công suất thấp để ảnh hưởng đến các thư viện phát triển nội bộ, StringDeDuplication có thể là một người chiến thắng nhanh chóng nếu bộ nhớ là một vấn đề. Nó sẽ ảnh hưởng đến tất cả các chuỗi trong JVM, nhưng G1 sẽ chỉ sử dụng thời gian rảnh rỗi để thực hiện nó. Bạn thậm chí có thể tinh chỉnh khi DeDuplication được tính bằng cách sử dụng một tham số khác (StringDeduplicationAgeThreshold)
  • Đối với một nhà phát triển lược tả mã của riêng mình, String.intern có thể thú vị hơn. Việc xem xét lại các mô hình miền là cần thiết để quyết định có nên gọi thực tập hay không và khi nào. Theo quy tắc của ngón tay cái, bạn có thể sử dụng thực tập khi bạn biết Chuỗi sẽ chứa tập hợp các giá trị giới hạn, như một loại tập hợp được liệt kê (ví dụ: Tên quốc gia, tháng, ngày trong tuần ...).
4

Là tham chiếu nhận xét, hãy xem: http://java-performance.info/string-intern-in-java-6-7-8/. Đó là tham khảo rất sâu sắc và tôi đã học được rất nhiều, tuy nhiên tôi không chắc chắn kết luận của nó là nhất thiết "một kích thước phù hợp với tất cả". Mỗi khía cạnh phụ thuộc vào nhu cầu của ứng dụng của riêng bạn - việc thực hiện các phép đo dữ liệu đầu vào thực tế là rất khuyến khích!

Yếu tố chính có thể phụ thuộc vào những gì bạn đang ở trong kiểm soát:

  • Bạn có toàn quyền kiểm soát lựa chọn GC? Trong một ứng dụng GUI chẳng hạn, vẫn còn một trường hợp mạnh mẽ được thực hiện để sử dụng Serial GC. (tổng dung lượng bộ nhớ thấp hơn rất nhiều cho quá trình này - hãy suy nghĩ 400 MB so với 1 GB cho một ứng dụng phức tạp vừa phải, và sẵn sàng hơn nhiều bộ nhớ phát hành, ví dụ: sau khi tăng đột biến về mức sử dụng). Vì vậy, bạn có thể chọn điều đó hoặc cung cấp cho người dùng của bạn tùy chọn. (Nếu heap vẫn nhỏ thì việc tạm dừng không nên là một vấn đề lớn).

  • Bạn có toàn quyền kiểm soát mã không?Tùy chọn G1GC thật tuyệt vời cho các thư viện của bên thứ ba (và các ứng dụng!) Mà bạn không thể chỉnh sửa.

Việc xem xét thứ hai (theo @ câu trả lời Zhongyu của) là String.intern có thể de-duplication các String đối tượng bản thân, trong khi G1GC nhất thiết chỉ có thể loại bỏ trùng lặp tin char[] lĩnh vực của họ.

Cân nhắc thứ ba có thể là mức sử dụng CPU, giả sử nếu tác động đến tuổi thọ pin của máy tính xách tay có thể là mối quan tâm đối với người dùng của bạn. G1GC sẽ chạy một chuỗi bổ sung dành riêng cho việc sao chép vùng heap. Ví dụ, tôi chơi với điều này để chạy Eclipse và tìm thấy nó gây ra một giai đoạn ban đầu của hoạt động CPU tăng lên sau khi bắt đầu (suy nghĩ 1 - 2 phút) nhưng nó được giải quyết trên một heap nhỏ hơn "trong sử dụng" và không rõ ràng (chỉ là mắt- balling người quản lý tác vụ) CPU trên cao hoặc chậm xuống sau đó. Vì vậy, tôi tưởng tượng một% nào đó của một lõi CPU sẽ được đưa lên trên de-sao chép (trong? Sau?) Các giai đoạn của bộ nhớ cao-khuấy. (Tất nhiên có thể có một khoản phí tương đương nếu bạn gọi String.intern ở mọi nơi, cũng sẽ chạy theo sau, nhưng sau đó ...)

Có thể bạn không cần chuỗi trùng lặp ở mọi nơi. Có lẽ khu vực nhất định của mã rằng:

  • thực sự ảnh hưởng đến việc sử dụng đống dài hạn,
  • tạo ra một tỷ lệ cao của chuỗi trùng lặp

Bằng cách sử dụng String.intern chọn lọc, các bộ phận khác của mã (có thể tạo ra các chuỗi tạm thời hoặc bán tạm thời) không trả giá.

Và cuối cùng, một plug nhanh chóng cho các tiện ích Ổi: Interner, trong đó:

Cung cấp hành vi tương đương với String.intern() cho loại không thay đổi khác

Bạn cũng có thể sử dụng cho Strings. Bộ nhớ có lẽ là (và nên là) mối quan tâm hiệu suất hàng đầu của bạn, vì vậy điều này có thể không áp dụng thường xuyên: tuy nhiên khi bạn cần phải giảm từng giọt tốc độ ra khỏi một số khu vực nóng, kinh nghiệm của tôi là tham chiếu yếu dựa trên Java Các giải pháp HashMap chạy hơi nhưng nhanh hơn so với triển khai C++ của JVM là String.intern(), ngay cả sau khi điều chỉnh các tùy chọn jvm. (Và tiền thưởng: bạn không cần phải điều chỉnh các tùy chọn JVM để mở rộng cho đầu vào khác nhau.)

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