Tôi đang cố gắng tìm nguồn gốc của rò rỉ bộ nhớ khó chịu trong chương trình Python/NumPy bằng cách sử dụng các phần mở rộng C/Cython và multiprocessing
.Gỡ lỗi rò rỉ bộ nhớ Python/NumPy
Mỗi quy trình con xử lý danh sách hình ảnh và mỗi bộ xử lý gửi mảng đầu ra (thường có kích thước khoảng 200-300MB) thông qua Queue
đến quy trình chính. Thiết lập bản đồ/giảm tiêu chuẩn hợp lý.
Như bạn có thể tưởng tượng một rò rỉ bộ nhớ có thể mất tỷ lệ ginormous với mảng này lớn, và có nhiều quy trình vui vẻ đi hơn 20GB RAM khi họ sẽ chỉ cần 5-6GB là ... gây phiền nhiễu.
Tôi đã thử chạy bản dựng gỡ lỗi của Python thông qua Valgrind và kiểm tra phần mở rộng của tôi cho rò rỉ bộ nhớ nhưng không tìm thấy gì.
Tôi đã kiểm tra mã Python của mình để tham chiếu đến các mảng của tôi và cũng sử dụng số allocation tracker của NumPy để kiểm tra xem các mảng của tôi có thực sự được phát hành hay không. Họ là.
Điều cuối cùng tôi đã đính kèm GDB vào một trong các quy trình của tôi (bad boy này hiện đang chạy ở RAM 27 GB và đếm) và bán một phần lớn đĩa vào đĩa. Nhiều đến ngạc nhiên của tôi, các tập tin được đổ đầy đã đầy zeroes! Khoảng 7G giá trị của số 0.
Đây có phải là hành vi phân bổ bộ nhớ tiêu chuẩn trong Python/NumPy không? Tôi đã bỏ lỡ một cái gì đó hiển nhiên mà sẽ giải thích có quá nhiều bộ nhớ được sử dụng cho không có gì? Làm thế nào tôi có thể quản lý bộ nhớ đúng cách?
EDIT: Đối với hồ sơ, tôi đang chạy NumPy 1.7.1 và Python 2.7.3.
EDIT 2: Tôi đã theo dõi quá trình với strace
, và có vẻ như nó vẫn không ngừng tăng điểm break của mỗi quá trình (sử dụng brk()
syscall).
CPython có thực sự giải phóng bộ nhớ đúng cách không? Điều gì về phần mở rộng C, mảng NumPy? Ai quyết định khi nào nên gọi brk()
, có phải là chính Python hay là thư viện cơ bản (libc
, ...)?
Dưới đây là nhật ký mẫu thử có nhận xét, từ một lần lặp (tức là một bộ hình ảnh đầu vào). Lưu ý rằng điểm ngắt tiếp tục tăng, nhưng tôi đã chắc chắn (với objgraph
) rằng không có mảng NumPy có ý nghĩa nào được giữ bên trong trình thông dịch Python.
# Reading .inf files with metadata
# Pretty small, no brk()
open("1_tif_all/AIR00642_1.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
open("1_tif_all/AIR00642_2.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
open("1_tif_all/AIR00642_3.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
open("1_tif_all/AIR00642_4.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
# This is where I'm starting the heavy processing
write(2, "[INFO/MapProcess-1] Shot 642: Da"..., 68) = 68
write(2, "[INFO/MapProcess-1] Shot 642: Vi"..., 103) = 103
write(2, "[INFO/MapProcess-1] Shot 642: Re"..., 66) = 66
# I'm opening a .tif image (752 x 480, 8-bit, 1 channel)
open("1_tif_all/AIR00642_3.tif", O_RDONLY) = 6
read(6, "II*\0JC\4\0", 8) = 8
mmap(NULL, 279600, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fbb000
munmap(0x7f9387fbb000, 279600) = 0
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 53) = 53
# Another .tif
open("1_tif_all/AIR00642_4.tif", O_RDONLY) = 6
read(6, "II*\0\266\374\3\0", 8) = 8
mmap(NULL, 261532, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fc0000
munmap(0x7f9387fc0000, 261532) = 0
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 51) = 51
brk(0x1aea97000) = 0x1aea97000
# Another .tif
open("1_tif_all/AIR00642_1.tif", O_RDONLY) = 6
read(6, "II*\0\220\253\4\0", 8) = 8
mmap(NULL, 306294, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fb5000
munmap(0x7f9387fb5000, 306294) = 0
brk(0x1af309000) = 0x1af309000
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 53) = 53
brk(0x1b03da000) = 0x1b03da000
# Another .tif
open("1_tif_all/AIR00642_2.tif", O_RDONLY) = 6
mmap(NULL, 345726, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fab000
munmap(0x7f9387fab000, 345726) = 0
brk(0x1b0c42000) = 0x1b0c42000
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 51) = 51
# I'm done reading my images
write(2, "[INFO/MapProcess-1] Shot 642: Fi"..., 72) = 72
# Allocating some more arrays for additional variables
# Increases by about 8M at a time
brk(0x1b1453000) = 0x1b1453000
brk(0x1b1c63000) = 0x1b1c63000
brk(0x1b2473000) = 0x1b2473000
brk(0x1b2c84000) = 0x1b2c84000
brk(0x1b3494000) = 0x1b3494000
brk(0x1b3ca5000) = 0x1b3ca5000
# What are these mmap calls doing here?
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9377df1000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9367be2000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93579d3000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93477c4000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93375b5000
munmap(0x7f93579d3000, 270594048) = 0
munmap(0x7f93477c4000, 270594048) = 0
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93579d3000
munmap(0x7f93375b5000, 270594048) = 0
mmap(NULL, 50737152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9354970000
munmap(0x7f9354970000, 50737152) = 0
brk(0x1b4cc6000) = 0x1b4cc6000
brk(0x1b5ce7000) = 0x1b5ce7000
EDIT 3:Is freeing handled differently for small/large numpy arrays? thể có liên quan. Tôi ngày càng bị thuyết phục rằng tôi chỉ đơn giản là phân bổ quá nhiều mảng mà không được phát hành cho hệ thống bởi vì nó thực sự là hành vi tiêu chuẩn. Sẽ cố gắng phân bổ mảng của tôi trước và tái sử dụng chúng khi cần thiết.
Bạn đang sử dụng gì để đọc tệp hình ảnh? Tôi đã có vấn đề rò rỉ bộ nhớ với các đối tượng PIL 'Image' trong quá khứ –
Tôi đang sử dụng các ràng buộc PyLibTiff. Và tôi đã giải quyết vấn đề này, hãy xem câu trả lời của tôi! –