TL/DR:Dỡ bỏ một module bằng Python
import gc, sys
print len(gc.get_objects()) # 4073 objects in memory
# Attempt to unload the module
import httplib
del sys.modules["httplib"]
httplib = None
gc.collect()
print len(gc.get_objects()) # 6745 objects in memory
CẬP NHẬT Tôi đã liên lạc với các nhà phát triển Python về vấn đề này và thực sự nó not going to be possible to unload a module hoàn toàn "trong vòng năm năm tới". (xem liên kết)
Hãy chấp nhận rằng Python thực sự không hỗ trợ dỡ mô-đun cho các vấn đề kỹ thuật nghiêm trọng, cơ bản, không thể vượt qua, trong 2.x.
Trong săn gần đây của tôi cho một memleak trong ứng dụng của tôi, tôi đã thu hẹp nó xuống để mô-đun, cụ thể là không có khả năng của tôi để rác thu thập một module dỡ. Sử dụng bất kỳ phương thức nào được liệt kê bên dưới để hủy mô-đun để lại hàng nghìn đối tượng trong bộ nhớ. Nói cách khác - tôi không thể bỏ một mô-đun bằng Python ...
Phần còn lại của câu hỏi là cố gắng thu thập rác một mô-đun bằng cách nào đó.
Hãy thử:
import gc
import sys
sm = sys.modules.copy() # httplib, which we'll try to unload isn't yet
# in sys.modules, so, this isn't the source of problem
print len(gc.get_objects()) # 4074 objects in memory
Hãy lưu một bản sao của sys.modules
cố gắng để khôi phục lại nó sau này. Vì vậy, đây là một đối tượng cơ sở 4074. Chúng ta nên quay trở lại lý tưởng bằng cách nào đó.
Hãy nhập một mô-đun:
import httplib
print len(gc.get_objects()) # 7063 objects in memory
Chúng tôi lên đến 7K đối tượng phi rác. Hãy thử xóa httplib
từ sys.modules
.
sys.modules.pop('httplib')
gc.collect()
print len(gc.get_objects()) # 7063 objects in memory
Điều đó không hiệu quả. Hmm, nhưng không có tài liệu tham khảo trong số __main__
? Ồ, vâng:
del httplib
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Hoan hô, giảm 300 đối tượng. Tuy nhiên, không có điếu xì gà, đó là cách hơn 4000 vật thể ban đầu. Hãy thử khôi phục sys.modules
từ bản sao.
sys.modules = sm
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Hmmm, cũng đó là vô nghĩa, không có thay đổi .. Có lẽ nếu chúng ta quét sạch globals ...
globals().clear()
import gC# we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
người dân địa phương?
locals().clear()
import gC# we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Điều gì sẽ xảy ra nếu chúng tôi imported
mô-đun bên trong exec
?
local_dict = {}
exec 'import httplib' in local_dict
del local_dict
gc.collect()
print len(gc.get_objects()) # back to 7063 objects in memory
Bây giờ, điều đó không công bằng, nó đã nhập nó vào __main__
, tại sao? Nó sẽ không bao giờ rời khỏi local_dict
... Argh! Chúng tôi trở lại được nhập đầy đủ httplib
. Có thể nếu chúng ta thay thế nó bằng một vật thể giả?
from types import ModuleType
import sys
print len(gc.get_objects()) # 7064 objects in memory
Đẫm máu ..... !!
sys.modules['httplib'] = ModuleType('httplib')
print len(gc.get_objects()) # 7066 objects in memory
Mô-đun chết, chết !!
import httplib
for attr in dir(httplib):
setattr(httplib, attr, None)
gc.collect()
print len(gc.get_objects()) # 6749 objects in memory
Được rồi, sau khi tất cả những nỗ lực, tốt nhất là 2675 (gần + 50%) từ điểm xuất phát ... Đó chỉ là từ một mô-đun ... Điều đó thậm chí không có gì lớn bên trong ...
Ok, bây giờ nghiêm túc, lỗi của tôi ở đâu? Làm cách nào để xóa mô-đun và xóa tất cả nội dung của mô-đun? Hoặc là mô-đun của Python một rò rỉ bộ nhớ khổng lồ?
nguồn đầy đủ trong đơn giản để sao chép hình thức: http://gist.github.com/450606
Có, nó tải không giới hạn số lượng mô-đun - đó là một máy chủ ứng dụng web chấp nhận sửa đổi mới của mã nguồn riêng của nó và tải lại nó (đó là nhiệm vụ web khá chuẩn). Sự rò rỉ IS từ thực tế là mã cũ vẫn còn tồn tại trong bộ nhớ, ngay cả khi được thay thế, ngay cả khi không thể truy cập được ... –
Python hỗ trợ các mô-đun dỡ tải. Chúng được thu thập rác, giống như mọi đối tượng khác trong Python. –
@Slava: Bạn có thể muốn xem mã nguồn để 'mod_python', có trình nhập riêng của nó được thiết kế để xử lý nạp lại các mô-đun mà không tạo rò rỉ bộ nhớ. Có thể có một số mã trong đó bạn có thể sử dụng. –