2017-02-07 19 views
8

Java 8 đã giới thiệu Chuỗi Chống trùng lặp có thể được bật bằng cách khởi chạy JVM với tùy chọn -XX:+UseStringDeduplication cho phép tiết kiệm bộ nhớ bằng cách tham chiếu các đối tượng tương tự String thay vì giữ các bản sao. Tất nhiên đó là hiệu quả thay đổi từ chương trình đến chương trình tùy thuộc vào việc sử dụng Strings nhưng tôi cho rằng nó có thể được coi là có lợi cho hầu hết các ứng dụng (nếu không phải tất cả) khiến tôi thắc mắc về một số điều:Tại sao/Khi bạn không muốn kích hoạt Java 8 UseStringDeduplication trong JVM?

là nó không được kích hoạt theo mặc định? Có phải vì chi phí liên quan đến việc chống trùng lặp hay đơn giản vì G1GC vẫn được coi là mới?

Có (hoặc có thể có) bất kỳ trường hợp cạnh nào mà bạn không muốn sử dụng PC không?

+3

Tôi nghĩ nó (như bạn đoán) * chủ yếu * chi phí thời gian chạy của de-duplication. –

+0

Không phải G1GC, nhưng bản sao trùng lặp có thể được coi là mới. – Holger

Trả lời

13

Các trường hợp Chuỗi de-duplication có thể gây hại bao gồm:

  • Rất nhiều dây nhưng một xác suất rất thấp của các bản sao: thời gian cần thiết của việc tìm kiếm các bản sao và thời gian và không gian trên cao của de-duping hashtable sẽ không được hoàn trả.
  • Xác suất hợp lý của các bản sao, nhưng hầu hết các chuỗi chết trong một vài chu kỳ GC : tính năng sao chép có ít lợi ích hơn nếu các de-dups ​​sắp được GC.

(Trường hợp thứ hai không phải là về chuỗi không tồn tại chu trình GC đầu tiên. Nó sẽ làm cho không có ý nghĩa cho GC để thậm chí thử để de-dup chuỗi mà nó biết là rác.)

Chúng tôi chỉ có thể suy đoán về lý do tại sao nhóm Java không bật tính năng loại bỏ theo mặc định, nhưng chúng ở vị trí tốt hơn để đưa ra quyết định hợp lý (tức là dựa trên bằng chứng) về bạn và I. sự hiểu biết là họ có quyền truy cập vào nhiều ứng dụng trong thế giới thực lớn để đo điểm chuẩn/thử các hiệu ứng của việc tối ưu hóa. Họ cũng có thể có liên hệ sâu sắc với một số đối tác hoặc tổ chức khách hàng có cơ sở mã tương tự lớn và mối quan tâm về hiệu quả ... họ có thể yêu cầu thông tin về việc tối ưu hóa nào thực sự hiệu quả.

1 - Điều này tùy thuộc vào giá trị của cài đặt StringDeduplicationAgeThreshold JVM. Điều này mặc định là 3 có nghĩa là (gần) một chuỗi phải tồn tại 3 bộ sưu tập nhỏ hoặc một bộ sưu tập lớn được xem xét để loại bỏ. Nhưng dù sao đi nữa, nếu một chuỗi bị loại bỏ và sau đó được tìm thấy không thể truy cập được trong thời gian ngắn sau đó, các chi phí bỏ trốn sẽ không được hoàn trả cho chuỗi đó.


Nếu bạn đang yêu cầu khi bạn nên xem xét tạo điều kiện cho de-duping, lời khuyên của tôi là để thử nó và xem nếu nó giúp trên một cơ sở cho mỗi ứng dụng. Nhưng bạn cần phải thực hiện một số điểm chuẩn cấp ứng dụng (cần nỗ lực!) Để đảm bảo rằng tính năng tách biệt là có lợi ...

Đọc kỹ JEP 192 cũng sẽ giúp bạn hiểu vấn đề và đưa ra phán quyết về cách chúng có thể áp dụng cho ứng dụng Java của bạn.

+0

Trường hợp thứ 2 không hoàn toàn đúng. Vì nó chỉ khử trùng các chuỗi tồn tại 3 GC. Tôi tìm thấy trang này được đọc tốt về chủ đề này http://java-performance.info/java-string-deduplication/ – keiki

+1

Nếu một chuỗi tồn tại 3 GC, bị loại bỏ và sau đó trở nên không thể truy cập ngay sau đó, việc loại bỏ overheads sẽ không được recouped. Đó là quan điểm của tôi. –

10

Tôi hoàn toàn hiểu rằng điều này không trả lời câu hỏi, chỉ muốn đề cập đến rằng jdk-9 giới thiệu thêm một tối ưu hóa mà là theo mặc định được gọi là:

-XX: + CompactStrings

trong đó Latin1 ký tự chiếm một byte đơn thay vì hai (thông qua một char). Vì sự thay đổi đó, nhiều phương thức nội bộ của String đã thay đổi - chúng hoạt động tương tự với người dùng, nhưng nội bộ chúng lại nhanh hơn trong nhiều trường hợp.

Cũng trong trường hợp các chuỗi để ghép hai chuỗi lại với nhau thông qua dấu cộng, javac sẽ tạo ra bytecode khác nhau.

Không có hướng dẫn bytecode mà nối hai Strings với nhau để javac sẽ tạo ra một

StringBuilder # thêm

trong back-end. Cho đến jdk-9.

Bây giờ các đại biểu bytecode để

StringConcatFactory # makeConcatWithConstants

hoặc

StringConcatFactory # makeConcat

qua hướng dẫn bytecode invokedynamic:

aload_0 
    1: aload_2 
    2: aload_1 
    3: invokedynamiC#8, 0 // InvokeDynamiC#0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 
    8: areturn 

Cách hai chuỗi được nối là một quyết định Thời gian chạy ngay bây giờ. nó có thể vẫn là một StringBuilder hoặc nó có thể là một nối của mảng byte, vv Tất cả bạn biết rằng điều này có thể thay đổi và bạn sẽ nhận được giải pháp nhanh nhất có thể.

EDIT

Tôi vừa mới sửa lỗi và thấy rằng có khá nhiều chiến lược về cách nối thêm những Strings:

private enum Strategy { 
    /** 
    * Bytecode generator, calling into {@link java.lang.StringBuilder}. 
    */ 
    BC_SB, 

    /** 
    * Bytecode generator, calling into {@link java.lang.StringBuilder}; 
    * but trying to estimate the required storage. 
    */ 
    BC_SB_SIZED, 

    /** 
    * Bytecode generator, calling into {@link java.lang.StringBuilder}; 
    * but computing the required storage exactly. 
    */ 
    BC_SB_SIZED_EXACT, 

    /** 
    * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}. 
    * This strategy also tries to estimate the required storage. 
    */ 
    MH_SB_SIZED, 

    /** 
    * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}. 
    * This strategy also estimate the required storage exactly. 
    */ 
    MH_SB_SIZED_EXACT, 

    /** 
    * MethodHandle-based generator, that constructs its own byte[] array from 
    * the arguments. It computes the required storage exactly. 
    */ 
    MH_INLINE_SIZED_EXACT 
} 

mặc định là:

MH_INLINE_SIZED_EXACT

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