2013-08-16 86 views
6

Tôi có một tính toán bên trong ST phân bổ bộ nhớ thông qua một Data.Vector.Unboxed.Mutable. Vectơ không bao giờ được đọc hoặc viết, cũng không có bất kỳ tham chiếu nào được giữ lại bên ngoài runST (theo hiểu biết tốt nhất của tôi). Vấn đề tôi có là khi tôi chạy tính toán ST của tôi nhiều lần, đôi khi tôi dường như giữ bộ nhớ cho vectơ xung quanh.Haskell: Rò rỉ bộ nhớ từ ST/GC không thu thập?

thống kê Allocation:

5,435,386,768 bytes allocated in the heap 
    5,313,968 bytes copied during GC 
    134,364,780 bytes maximum residency (14 sample(s)) 
    3,160,340 bytes maximum slop 
      518 MB total memory in use (0 MB lost due to fragmentation) 

Ở đây tôi gọi runST 20x với giá trị khác nhau cho tính toán của tôi và một vector 128MB (một lần nữa - không sử dụng, không được trả lại hoặc tham chiếu bên ngoài của ST). Các cư trú tối đa có vẻ tốt, về cơ bản chỉ là vector của tôi cộng với một vài MB của các công cụ khác. Nhưng tổng số bộ nhớ sử dụng chỉ ra rằng tôi có bốn bản sao của vectơ hoạt động cùng một lúc. Điều này quy mô hoàn hảo với kích thước của vector, cho 256MB, chúng tôi nhận được 1030MB như mong đợi.

Sử dụng vector 1 GB hết bộ nhớ (4x1GB + trên không> 32 bit). Tôi không hiểu lý do tại sao RTS giữ dường như không sử dụng, bộ nhớ unreferenced xung quanh thay vì chỉ GC'ing nó, ít nhất là tại điểm mà một phân bổ nếu không sẽ thất bại.

Chạy với + RTS -S tiết lộ như sau:

Alloc Copied  Live GC GC  TOT  TOT Page Flts 
    bytes  bytes  bytes user elap user elap 
134940616  13056 134353540 0.00 0.00 0.09 0.19 0 0 (Gen: 1) 
    583416  6756 134347504 0.00 0.00 0.09 0.19 0 0 (Gen: 0) 
    518020  17396 134349640 0.00 0.00 0.09 0.19 0 0 (Gen: 1) 
    521104  13032 134359988 0.00 0.00 0.09 0.19 0 0 (Gen: 0) 
    520972  1344 134360752 0.00 0.00 0.09 0.19 0 0 (Gen: 0) 
    521100  828 134360684 0.00 0.00 0.10 0.19 0 0 (Gen: 0) 
    520812  592 134360528 0.00 0.00 0.10 0.19 0 0 (Gen: 0) 
    520936  1344 134361324 0.00 0.00 0.10 0.19 0 0 (Gen: 0) 
    520788  1480 134361476 0.00 0.00 0.10 0.20 0 0 (Gen: 0) 
134438548  5964 268673908 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    586300  3084 268667168 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    517840  952 268666340 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520920  544 268666164 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520780  428 268666048 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520820  2908 268668524 0.00 0.00 0.19 0.38 0 0 (Gen: 0) 
    520732  1788 268668636 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    521076  564 268668492 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    520532  712 268668640 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    520764  956 268668884 0.00 0.00 0.19 0.39 0 0 (Gen: 0) 
    520816  420 268668348 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    520948  1332 268669260 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    520784  616 268668544 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    521416  836 268668764 0.00 0.00 0.20 0.39 0 0 (Gen: 0) 
    520488  1240 268669168 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520824  1608 268669536 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520688  1276 268669204 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520252  1332 268669260 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
    520672  1000 268668928 0.00 0.00 0.20 0.40 0 0 (Gen: 0) 
134553500  5640 402973292 0.00 0.00 0.29 0.58 0 0 (Gen: 0) 
    586776  2644 402966160 0.00 0.00 0.29 0.58 0 0 (Gen: 0) 
    518064  26784 134342772 0.00 0.00 0.29 0.58 0 0 (Gen: 1) 
    520828  3120 134343528 0.00 0.00 0.29 0.59 0 0 (Gen: 0) 
    521108  756 134342668 0.00 0.00 0.30 0.59 0 0 (Gen: 0) 

Đây có vẻ như chúng ta có vượt ~ 128MB 'byte sống'.

Hồ sơ +RTS -hy về cơ bản chỉ nói chúng tôi phân bổ 128MB:

http://imageshack.us/a/img69/7765/45q8.png

tôi đã cố gắng tái tạo hành vi này trong một chương trình đơn giản hơn, nhưng ngay cả với sao chép các thiết lập chính xác với ST, một Reader chứa Vector, cùng monad/chương trình cấu trúc vv các chương trình thử nghiệm đơn giản không hiển thị này. Đơn giản hóa chương trình lớn của tôi, hành vi cũng dừng lại khi loại bỏ hoàn toàn mã không liên quan.

Qs:

  • Am Tôi thực sự giữ vector này khoảng 4 lần trong số 20?
  • Nếu có, làm thế nào để tôi thực sự kể từ +RTS -Hymaximum residency tuyên bố tôi không và tôi có thể làm gì để ngăn chặn hành vi này?
  • Nếu không, tại sao Haskell không GC'ing nó và chạy ra khỏi không gian địa chỉ/bộ nhớ, và những gì tôi có thể làm gì để ngăn chặn hành vi này?

Cảm ơn!

+2

Bộ nhớ được sử dụng thường gấp đôi số lượng lưu trú tối đa trở lên, tùy thuộc vào phân bổ và mẫu thu thập. Vì vậy, tổng dung lượng 518MB được sử dụng không đáng báo động. Hãy thử nói với GHC rằng chỉ có quá nhiều bộ nhớ để sử dụng, ví dụ '$ ./foo + RTS -M256M', để buộc nó phải thu thập trước đó. Nhưng "cũng không có bất kỳ tài liệu tham khảo nào được giữ lại bên ngoài runST" có thể là không đúng sự thật, bạn thực sự có thể bị rò rỉ. Một trong những sẽ cần phải xem mã nếu đó là trường hợp. Tuy nhiên, –

+0

@DanielFischer 518MB là ~ 4x. Chẳng phải vụ tai nạn ngoài bộ nhớ với vectơ 1GB chỉ ra rằng GHC * không thể * thu thập bộ nhớ? + RTS -M256M không thành công với 'Heap exhausted'. Các vector được tạo ra, đặt bên trong một môi trường Reader, đó là nó. Không có gì khác, không chắc chắn những gì khác tôi có thể làm để tránh rò rỉ bất kỳ tài liệu tham khảo sau khi rời khỏi ST/Reader. Như tôi đã nói, tôi không thể tái tạo vấn đề này trong một chương trình đơn giản hơn. Nó có vẻ khá ngẫu nhiên. – NBFGRTW

+0

Vâng, 4 × có thể xảy ra với mẫu phân bổ đúng/sai. Vụ tai nạn ngoài bộ nhớ có thể chỉ ra rằng GHC không biết nó nên thu thập, nhưng với điều đó '-M256M' gây ra" đống cạn kiệt ", có vẻ như có gì đó liên quan đến con thú. –

Trả lời

2

Tôi nghi ngờ đây là lỗi trong GHC và/hoặc RTS.

Trước tiên, tôi tự tin không có rò rỉ không gian thực tế hoặc bất kỳ thứ gì như thế.

Lý do:

  • Các vector không bao giờ được sử dụng bất cứ nơi nào. Không đọc, không được viết, không được tham chiếu. Nó sẽ được thu thập sau khi runST được thực hiện. Ngay cả khi tính toán ST trả về một Int đơn lẻ ngay lập tức được in ra để đánh giá nó, vấn đề bộ nhớ vẫn tồn tại. Không có tham chiếu đến dữ liệu đó.
  • Mỗi chế độ lược tả mà RTS cung cấp là trong thỏa thuận bạo lực mà tôi chưa bao giờ thực sự có nhiều hơn giá trị bộ nhớ của một thẻ được phân bổ/tham chiếu. Mỗi biểu đồ thống kê và đẹp đều nói điều đó.

Bây giờ, đây là một chút thú vị. Nếu tôi buộc GC theo cách thủ công bằng cách gọi System.Mem.performGC sau mỗi lần chạy hàm của tôi, vấn đề sẽ biến mất hoàn toàn. Vì vậy, chúng tôi có một trường hợp mà thời gian chạy có giá trị GB bộ nhớ mà (có thể hiểu được!) Có thể được khai hoang bởi GC và thậm chí theo thống kê riêng của nó không được giữ bởi bất kỳ ai nữa. Khi chạy ra khỏi bộ nhớ của nó, thời gian chạy không thu thập, nhưng thay vào đó yêu cầu hệ điều hành để có thêm bộ nhớ. Và ngay cả khi điều đó cuối cùng không thành công, thời gian chạy vẫn không thu thập (mà sẽ đòi lại GB bộ nhớ, rõ ràng) nhưng thay vào đó chọn chấm dứt chương trình với lỗi ngoài bộ nhớ.

Tôi không có chuyên gia về Haskell, GHC hoặc GC. Nhưng điều này trông rất kinh khủng với tôi. Tôi sẽ báo cáo lỗi này.

+0

Bạn đã bao giờ nhận được để báo cáo điều này? – jberryman