2012-05-09 41 views
10

Vì tài liệu thư viện nói CString được tạo với newCString phải được giải phóng với chức năng free. Tôi đã mong đợi rằng khi CString được tạo ra nó sẽ mất một số bộ nhớ và khi nó được phát hành với sử dụng bộ nhớ free sẽ đi xuống, nhưng nó đã không! Dưới đây là mã ví dụ:Giải phóng bộ nhớ được phân bổ với newCString

module Main where 

import Foreign 
import Foreign.C.String 
import System.IO 

wait = do 
    putStr "Press enter" >> hFlush stdout 
    _ <- getLine 
    return() 

main = do 
    let s = concat $ replicate 1000000 ['0'..'9'] 
    cs <- newCString s 
    cs `seq` wait -- (1) 

    free cs 
    wait -- (2) 

Khi chương trình dừng lại ở (1), htop chương trình cho thấy rằng việc sử dụng bộ nhớ là ở đâu đó xung quanh 410M - đây là OK. Tôi nhấn enter và chương trình dừng lại ở dòng (2), nhưng mức sử dụng bộ nhớ vẫn là 410M mặc dù csfree d!

Làm cách nào có thể? Chương trình tương tự được viết bằng C hoạt động như mong muốn. Tôi đang thiếu gì ở đây?

+1

Bạn đang sử dụng phiên bản GHC nào? Khả năng trả lại bộ nhớ cho hệ điều hành chỉ được thêm vào GHC vào năm ngoái. –

+0

Đầu ra 'ghc --version'' Hệ thống biên dịch Glorious Glasgow Haskell, phiên bản 7.4.1' –

Trả lời

8

Vấn đề là free chỉ báo cho bộ thu gom rác mà hiện tại, nó có thể thu thập chuỗi. Điều đó không thực sự buộc các nhà sưu tập rác để chạy mặc dù - nó chỉ chỉ ra rằng CString bây giờ là rác. Nó vẫn còn lên đến GC để quyết định khi nào chạy, dựa trên heuristics áp suất heap.

Bạn có thể buộc bộ sưu tập chính bằng cách gọi performGC ngay sau khi gọi tới free, làm giảm bộ nhớ ngay lập tức xuống 5 triệu.

Ví dụ: chương trình này:

import Foreign 
import Foreign.C.String 
import System.IO 
import System.Mem 

wait = do 
    putStr "Press enter" >> hFlush stdout 
    _ <- getLine 
    return() 

main = do 
    let s = concat $ replicate 1000000 ['0'..'9'] 
    cs <- newCString s 
    cs `seq` wait -- (1) 

    free cs 
    performGC 
    wait -- (2) 

cư xử như mong đợi, với cấu hình bộ nhớ sau - dấu chấm màu đỏ đầu tiên là cuộc gọi đến performGC, ngay lập tức deallocating chuỗi. Chương trình sau đó di chuyển khoảng 5M cho đến khi chấm dứt.

enter image description here

+0

Cảm ơn bạn rất nhiều. Tôi không biết rằng 'malloc' /' free' trong ghc làm việc theo cách này. Tôi đã thử 'performGC' và nó thực sự hoạt động. Vâng, câu hỏi này phát sinh khi tôi đã thử nghiệm như thế nào ràng buộc của tôi để làm việc thư viện C nhất định. Tôi đã thử nghiệm chúng với số lượng lớn các chuỗi C và đã rất ngạc nhiên khi biết rằng bộ nhớ không được phát hành. Có vẻ như bí ẩn này đã được giải quyết ngay bây giờ) –

+2

Tôi đoán tôi không thể tranh luận với bằng chứng của bạn rằng 'performGC' thực sự hoạt động, nhưng đây là những gì tôi giả định là câu trả lời cho đến khi tôi đi và nhìn vào [nguồn] (http: // hackage.haskell.org/packages/archive/base/4.5.0.0/doc/html/src/Foreign-Marshal-Alloc.html#free) - có vẻ như với tôi như 'free' thực sự gọi hàm C là miễn phí () '. Làm thế nào mà tương tác với GC? –

+2

Tôi nghi ngờ là bởi vì bộ nhớ không thực sự được phát hành cho hệ điều hành từ bể mạch GHC cho đến khi GC chạy. Vì vậy, bạn sẽ có thể tái sử dụng khối bộ nhớ từ Haskell, nó chỉ không được đưa trở lại hệ điều hành nào được nêu ra. –

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