2016-02-13 14 views
15

Tôi là người mới, và tôi đã đọc về Bộ sưu tập rác từ hai câu trả lời đầu tiên here.Làm thế nào để các đối tượng không thể thay đổi giúp giảm chi phí do Bộ sưu tập rác?

Bây giờ biện minh cho việc sử dụng đối tượng không thể thay đổi ngay cả khi người lập trình phải tạo đối tượng mới, so với sử dụng đối tượng hiện có (trong ứng dụng đa luồng), this tutorial nói rằng chi phí tạo đối tượng được tạo bởi giảm trong bộ nhớ overhead do thu gom rác thải, và việc loại bỏ mã để bảo vệ vật có thể thay đổi từ đề can thiệp và nhất quán bộ nhớ lỗi:

tác động của việc tạo ra đối tượng thường được đánh giá quá cao, và có thể bù đắp bởi một số hiệu quả kết hợp với các đối tượng bất biến. Chúng bao gồm giảm chi phí do thu gom rác thải và việc loại bỏ mã cần thiết để bảo vệ các đối tượng có thể biến đổi khỏi sự cố tham nhũng .

Câu hỏi đặt ra là như thế nào? Những gì hiện Garbage Bộ sưu tập có liên quan đến Mutability hoặc Immutability của các đối tượng?

+3

GC hiện đại cực kỳ hiệu quả với các đối tượng "chết trẻ". Đừng ngại tạo và sử dụng các đối tượng với tuổi thọ ngắn; nhưng hãy cẩn thận với việc giữ các đối tượng tham chiếu trong thời gian dài hơn (ví dụ: để lưu bộ nhớ đệm). Vấn đề là không thực sự về bất biến, nhiều hơn về tuổi thọ. – ZhongYu

+1

Trong hướng dẫn bạn đã liên kết, cụm từ chính xác là _ "giảm chi phí do thu gom rác thải" _. Không có từ "bộ nhớ" trong đó. Bạn nên sửa nó trong câu hỏi của bạn, bởi vì các đối tượng bất biến thực sự có thể tiêu thụ nhiều bộ nhớ hơn (vì bạn buộc phải tạo một bộ nhớ mới nếu bạn muốn thay đổi thứ gì đó hiện có), trong khi giảm gánh nặng chung trên GC. Thêm chi tiết trong câu trả lời của tôi dưới đây. –

Trả lời

11

Đôi khi bạn phân bổ ít hơn khi đối tượng không thay đổi.

Ví dụ đơn giản

Date getDate(){ 
    return copy(this.date); 
} 

tôi phải sao chép Date mỗi khi tôi chia sẻ nó vì nó là có thể thay đổi hoặc người gọi sẽ có thể đột biến nó. Nếu getDate được gọi rất nhiều, tỷ lệ phân bổ sẽ tăng đáng kể và điều này sẽ gây áp lực lên GC

Mặt khác, Java-8 ngày là không thay đổi

LocalDate getDate(){ 
    return this.date; 
} 

Chú ý rằng tôi không cần để sao chép ngày (phân bổ một đối tượng mới) vì bất biến (tôi rất vui khi chia sẻ đối tượng với bạn bởi vì tôi biết rằng bạn không thể thay đổi nó).

Bây giờ bạn có thể nghĩ làm cách nào để áp dụng cấu trúc dữ liệu phức tạp hoặc hữu ích này mà không gây ra sự phân bổ lớn (do bản sao phòng thủ), bạn hoàn toàn đúng, nhưng có một nghệ thuật được gọi là functional programmingpersistent data structures (ví dụ: bạn có được ảo tưởng rằng đó là một bản sao mới, trong đó thực tế bản sao chia sẻ rất nhiều từ bản gốc).

Bạn không nên ngạc nhiên khi hầu hết các ngôn ngữ chức năng (tất cả những ngôn ngữ mà tôi biết) đều là rác được thu thập.

+0

Cảm ơn bạn rất nhiều.Trong khi câu trả lời khác hơn hai đoạn văn cuối cùng đã làm cho nó rõ ràng đối với tôi, tôi không thể hiểu rõ hai đoạn văn cuối cùng. Bạn có thể ném một số ánh sáng ở đó nếu bạn có thời gian, nếu không thì tốt. Cảm ơn bạn một lần nữa cho câu trả lời. – Solace

+0

@Solace là bạn có biết về cấu trúc dữ liệu chức năng không? họ làm rất nhiều thủ thuật để tránh các bản sao phòng thủ "ngây thơ". Ví dụ: –

+3

@Solace One (rất đơn giản, cổ điển) là danh sách: Khi bạn có danh sách không thay đổi, ví dụ: một danh sách '[a, b, c, d, e]', sau đó bạn có thể thực hiện cấu trúc dữ liệu này (không thay đổi!) theo cách cho phép bạn xóa "" hai thành phần đầu tiên khỏi danh sách này - nhưng điều này sẽ ** không ** tạo danh sách mới hoặc thực sự sửa đổi danh sách hiện tại. Thay vào đó, bạn sẽ có được "danh sách con" '[c, d, e]' được hỗ trợ bởi cùng một bộ nhớ như là bộ nhớ đầu tiên. Ngoài ra, hãy xem https://en.wikipedia.org/wiki/Persistent_data_structure và các câu hỏi về stackoverflow có liên quan. – Marco13

8

Các đối tượng không thể thay đổi không cần bản sao phòng thủ nếu bạn đang chia sẻ chúng qua các bối cảnh (.e.g mã gọi điện mà bạn không tin tưởng) hoặc cho an toàn luồng. Điều này có nghĩa là số lần đọc các đối tượng không thay đổi có thể thấp hơn về lượng rác.

Mặt khác, mỗi khi bạn thay đổi một đối tượng bất biến, bạn phải tạo đối tượng mới cho dù điều này là cần thiết hay không. Về vấn đề này, các đối tượng bất biến có thể tạo ra nhiều rác hơn.

Câu hỏi thực sự là bạn đang tạo ra nhiều lần đọc, hoặc viết nhiều (hoặc trộn) Tùy thuộc vào cách sử dụng Các đối tượng không thể lưu có thể lưu đối tượng hoặc tạo nhiều đối tượng hơn, do đó sử dụng đối tượng không thể thay đổi hoặc có thể thay đổi về trường hợp sử dụng cụ thể của bạn.Lưu ý: hầu hết thời gian, tính chính xác là xa, quan trọng hơn nhiều so với hiệu suất, và trong khi nói chung các đối tượng không thể có IMHO trên cao, nó dễ dàng hơn để chứng minh tính chính xác của các mô hình dữ liệu bằng cách sử dụng các đối tượng không thể thay đổi được. giá trị sử dụng các vật thể không thay đổi để rõ ràng và dễ dàng lý luận một mình.

+2

Tôi đã đánh dấu câu trả lời khác như được chấp nhận vì ví dụ đó, nhưng tôi rất biết ơn lời khuyên. Nó có giá trị đối với tôi. Cảm ơn bạn rất nhiều. – Solace

5

Trong this article Brian Goetz giải thích điều đó một cách độc đáo. Về cơ bản, nó có liên quan với cách thu gom rác thải hoạt động. Nó có ít việc phải làm nếu các đối tượng mới tham khảo những cái cũ hơn ngược lại.

Trích từ bài viết liên kết với các lớp ví dụ dưới đây:

public class MutableHolder { 
    private Object value; 
    public Object getValue() { return value; } 
    public void setValue(Object o) { value = o; } 
} 

public class ImmutableHolder { 
    private final Object value; 
    public ImmutableHolder(Object o) { value = o; } 
    public Object getValue() { return value; } 
} 

Trong hầu hết các trường hợp, khi một đối tượng giữ được cập nhật để tham chiếu đến một đối tượng khác nhau , các vật ám chỉ mới là một đối tượng thanh niên. Nếu chúng tôi cập nhật số MutableHolder bằng cách gọi setValue(), chúng tôi đã tạo một tình huống trong đó đối tượng cũ tham chiếu đến trẻ hơn. Mặt khác, bằng cách tạo đối tượng ImmutableHolder mới thay thế, một đối tượng trẻ hơn là tham chiếu một đối tượng cũ hơn.

Tình huống thứ hai, nơi hầu hết các đối tượng trỏ đến các đối tượng cũ hơn, là nhẹ nhàng hơn nhiều trên bộ thu gom rác thế hệ. Nếu một số MutableHolder sống trong thế hệ cũ bị đột biến, tất cả các đối tượng trên thẻ có chứa MutableHolder phải được quét để tham khảo cũ để trẻ tại bộ sưu tập nhỏ tiếp theo.

Việc sử dụng tài liệu tham khảo có thể thay đổi đối với các đối tượng chứa lâu dài tăng công việc để theo dõi các tham chiếu cũ đến lúc thu thập thời gian.

phân tích thoát

Về lo ngại rằng rất nhiều các đối tượng được tạo ra bởi vì bạn tạo một đối tượng mới bất cứ khi nào bạn cần phải thay đổi một hiện có, cơ chế phân bổ đối tượng được cải thiện nhiều trong JVM mới nhất.

Hãy xem escape analysis (cũng được đề cập trong bài viết được liên kết). Nhiều đối tượng sẽ không được cấp phát trên heap (nhưng được sắp xếp/phân bổ trên stack), do đó GC sẽ không có gì để làm với chúng (thực sự GC không biết rằng các đối tượng đó tồn tại ở tất cả).

Mặc dù không liên quan đến bất biến, cơ chế phân tích thoát có thể được sử dụng hiệu quả hơn trong ngữ cảnh bất biến (ví dụ là đối tượng Person không được thay đổi trong khi gọi phương thức trong tài liệu Oracle được liên kết).

+1

Mặc dù nó không * nghiêm chỉnh * liên quan đến bất biến, từ khóa ** "phân tích thoát" ** thực sự đáng để chỉ ra trong ngữ cảnh này (tôi đã tạo ra một câu trả lời riêng cho điều đó, nhưng nó cũng được giải thích trong bài viết mà bạn kêt nôi đên). +1 – Marco13

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