2014-06-20 15 views
8

Trong Advanced Swift nói chuyện từ WWDC 2014, loa cho ví dụ này của một hàm memoizer sử dụng Generics:Lifetime bộ nhớ giữ lại trong Swift đóng cửa

func memoize<T: Hashable, U>(body: (T)->U) -> (T)->U { 
    var memo = Dictionary<T, U>() 
    return { x in 
     if let q = memo[x] { return q } 
     let r = body(x) 
     memo[x] = r 
     return r 
    } 
} 

Tôi đang gặp rắc rối quấn quanh đầu tôi suốt cuộc đời của số memo var. Mỗi lời gọi hàm fibonacci được ghi nhớ có chứa tham chiếu mạnh mẽ không? Và nếu vậy, làm thế nào bạn sẽ phát hành bộ nhớ đó khi bạn đang thực hiện với nó?

Trả lời

12

Trong thuật ngữ C/Objective-C Blocks, memo là một __block biến (trong Swift, bạn không cần phải viết rõ ràng __block để nắm bắt các biến theo tham chiếu). Biến có thể được gán vào trong một khối (đóng) và tất cả các phạm vi thấy biến đó sẽ thấy các thay đổi từ bất kỳ biến nào khác (chúng có chung tham chiếu đến biến). Biến sẽ có giá trị miễn là một số khối (đóng) sử dụng nó (chỉ có một khối sử dụng nó trong trường hợp này) vẫn còn sống. Sau khi khối cuối cùng sử dụng nó được deallocated, biến đi ra khỏi phạm vi. Cách hoạt động là chi tiết triển khai.

Nếu biến này có kiểu con trỏ đối tượng, thì đối tượng được trỏ tới sẽ được giữ lại bởi bất kỳ khối nào nắm bắt được nó. Tuy nhiên, trong trường hợp này, biến là Dictionary, một loại cấu trúc, là một loại giá trị. Vì vậy, không có quản lý bộ nhớ để lo lắng về. Biến là cấu trúc và cấu trúc tồn tại miễn là biến. (Bản thân struct có thể cấp phát bộ nhớ ở nơi khác, và giải phóng nó trong destructor của nó, nhưng nó được xử lý hoàn toàn bởi cấu trúc và bên ngoài không nên biết hoặc quan tâm đến nó.)

Thông thường, không cần phải lo lắng về cách __block biến làm việc nội bộ. Nhưng về cơ bản, biến được bọc trong một loại "đối tượng" đơn giản hóa, với "biến" thực tế là một trường của "đối tượng" này, được quản lý bộ nhớ thông qua việc đếm tham chiếu. Các khối nắm bắt chúng giữ "tham chiếu mạnh" đối với đối tượng giả này - khi một khối được tạo trên heap (về mặt kỹ thuật, khi chúng được sao chép từ các khối ngăn xếp đến đống) sử dụng biến số __block này, nó sẽ tăng số lượng tham chiếu ; khi một khối sử dụng nó được deallocated, nó làm giảm số lượng tham chiếu. Khi số tham chiếu đi tới 0, đối tượng giả này được deallocated, hãy gọi hàm hủy thích hợp cho kiểu biến của nó đầu tiên.

Để trả lời câu hỏi của bạn, "chức năng mã hóa được ghi nhớ" là một khối (đóng). Và đó là điều có liên quan chặt chẽ đến bất kỳ thứ gì giữ biến số memo. "Invocations" không có tham chiếu mạnh hoặc yếu; khi một hàm được gọi, nó sử dụng tham chiếu mà chính hàm đó có.Thời gian tồn tại của biến memo là tuổi thọ của các "chức năng fibonacci nhớ" trong trường hợp này, bởi vì nó là việc đóng cửa chỉ để chụp biến này.

2

Khối bên trong (giá trị trả lại) sẽ giữ lại ghi nhớ có nghĩa là bản ghi nhớ sẽ vẫn tồn tại miễn là blck được trả về được giữ lại.

Một bản ghi nhớ mới sẽ được tạo mỗi khi chức năng ghi nhớ được gọi. Việc gọi khối được trả về sẽ không tạo ra các bản ghi nhớ mới.

Toàn bộ bộ nhớ sẽ được giải phóng khi khối được trả về nằm ngoài phạm vi.

3

Mỗi lần gọi memoize() sẽ tự tạo biến số memo riêng, độc lập với các lời gọi khác. Nó tồn tại chừng nào sự đóng lại ám chỉ nó sống; khi đóng cửa được giải phóng, các biến bị bắt bởi nó (trong trường hợp này là memo) cũng được giải phóng.

Bạn có thể nghĩ về điều này như trở về một cấu trúc giống như trong giả này:

struct Closure<T,U> 
{ 
    var memo: Dictionary<T, U> 
    func call(t: T): U 
    { 
     .... 
    } 
} 

func memoize<T: Hashable, U>(body: (T)->U) -> Closure<T,U> 
{ 
    return Closure(memo: Dictionary<T, U>()) 
} 
+0

Không giống như mã đó, vì nhiều lần đóng có thể nắm bắt biến này và biến sẽ được chia sẻ trạng thái giữa tất cả các lần đóng. Cộng với tình trạng biến cũng được chia sẻ giữa việc đóng cửa và mã ngoài việc đóng cửa (ví dụ mã trong 'chức năng memoize' trực tiếp có thể đọc và viết 'memo' quá). – newacct

+1

@newacct Mã này là để minh họa cho trường hợp cụ thể này, không phải đóng cửa nói chung. – hamstergene

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