2016-10-14 59 views
10

Trong phiên bản trước của Python (Tôi không nhớ cái nào), hãy gọi gc.get_referrers trên một chuỗi tùy ý có thể được sử dụng để lấy tham chiếu đến số interned dict, sau đó có thể được truy vấn cho độ dài của nó.Làm thế nào để xác định số lượng chuỗi nội bộ trong Python 2.7.5?

Nhưng điều này không còn hoạt động trong Python 2.7.5: gc.get_referrers(...) không còn bao gồm số interned dict trong danh sách nó trả về.

Có cách nào khác, bằng Python 2.7.5, để xác định số chuỗi nội bộ không? Nếu vậy, làm thế nào?

+2

Tại sao bạn quan tâm? Bạn đang cố gắng thực hiện điều gì với bản hack đặc thù ở mức độ thấp như vậy? Oh yeah, 2.7.12 là phiên bản hiện tại, vậy tại sao bạn cần mức độ chi tiết này trong một bản phát hành đã lên tới 3 tuổi? Tôi không có ý là thù địch, nhưng tôi không thể hiểu tại sao điều này sẽ * bao giờ * quan trọng. – cco

+1

(a) Tôi quan tâm, bởi vì tôi quan tâm đến việc hiểu cách sử dụng bộ nhớ của các quy trình Python của chúng tôi, và đây là một điểm dữ liệu bổ sung. (b) Tôi quan tâm đến Python 2.7.5 vì đó là phiên bản mà chúng tôi sử dụng trong sản phẩm của mình, mặc dù tôi nghi ngờ câu trả lời sẽ giống nhau trong Python 2.7.12. – jchl

+0

Cảm ơn câu trả lời. Tôi chưa bao giờ dành thời gian để điều tra kích thước của lệnh 'interned', bởi vì các chuỗi (không phải chữ) trong các ứng dụng của tôi luôn có hậu quả hơn, vì vậy đảm bảo tôi chỉ có một bản sao của mỗi chuỗi đó nơi tôi đã dành thời gian của mình. Kết quả là, tôi vẫn tò mò muốn biết mục tiêu của bạn là gì - nếu bạn có thông tin bạn đang yêu cầu, bạn sẽ sử dụng nó như thế nào? – cco

Trả lời

2

Bạn có thể sắp xếp làm điều này, nhưng tất cả các tùy chọn đều lộn xộn và đầy đủ các điểm đến gần như vô dụng, vì vậy trước tiên, hãy cân nhắc xem bạn có thực sự muốn.

Thực hiện chuỗi không kéo dài tuổi thọ của nó. Bạn không cần phải lo lắng về việc dict tồn tại phát triển mãi mãi, đầy đủ các chuỗi bạn không cần. Do đó, việc thực hiện chuỗi ký tự không thể là một vấn đề bộ nhớ thực tế và việc học được bao nhiêu chuỗi đã được thực tập có thể khá vô ích.

Nếu bạn vẫn muốn thực hiện việc này, hãy xem xét các tùy chọn của bạn.


Đúng cách có thể là sử dụng triển khai thực hiện của riêng bạn ... ngoại trừ hỗ trợ tham chiếu yếu kém của Python không cho phép bạn tạo tham chiếu yếu đến chuỗi. Điều đó có nghĩa là nếu bạn thử cách tiếp cận này, bạn bị kẹt hoặc đi qua các trình bao bọc chuỗi có thể tham chiếu yếu của riêng bạn hoặc giữ các chuỗi ký tự tồn tại mãi mãi. Cả hai tùy chọn đều khủng khiếp.


Thực tế là chức năng in thông tin bạn đang yêu cầu ... nhưng nó cũng thực hiện mọi thứ. Sự tồn tại của nó là một chi tiết thực hiện, và nó chỉ có thể truy cập thông qua API C, vì vậy chúng ta sẽ cần phải sử dụng ctypes.pythonapi để có được nó.

import ctypes 

_Py_ReleaseInternedStrings = ctypes.pythonapi._Py_ReleaseInternedStrings 

_Py_ReleaseInternedStrings.argtypes =() 
_Py_ReleaseInternedStrings.restype = None 

_Py_ReleaseInternedStrings() 

Output:

releasing 3461 interned strings 
total size of all interned strings: 33685/0 mortal/immortal 

Tổng kích thước được liệt kê là khoản tiền có độ dài chuỗi, vì vậy họ không bao gồm tiêu đề đối tượng hoặc Terminators null.


Có thể bạn không hài lòng về việc phải giải phóng tất cả các chuỗi nội bộ mỗi khi bạn muốn kiểm tra số lượng có. Thật không may, Python không phơi bày dict interned, thậm chí thông qua C API hoặc thông qua GC hooks. Bạn có thể thử những gì khác? Vâng, chuyển sang các tùy chọn thậm chí còn điên rồ hơn, có trình gỡ lỗi.

ecatmur đăng tải một crazy hack tung ra một quá trình GDB trong chế độ không giám sát và sử dụng một breakpoint có điều kiện để có được ít errnomap, một dict rất giống với interned dict bạn muốn truy cập. Điều này có thể được điều chỉnh để truy cập vào số interned dict thay thế. Nó sẽ là rất cao không di động và cực kỳ khó khăn để duy trì.


Khởi chạy trình gỡ lỗi cũng là một tùy chọn khủng khiếp. Bạn có thể thử những gì khác? Vâng, bạn luôn có thể xây dựng bản dựng Python tùy chỉnh của riêng mình. Tải nguồn từ python.org, thêm

PyObject * 
AwfulHackToGetTheInternedDict(void) 
{ 
    if (interned == NULL) { 
     // No interned dict yet. 
     Py_RETURN_NONE; 
    } 
    Py_INCREF(interned); 
    return interned; 
} 

để Objects/stringobject.c, xây dựng và cài đặt. Có thể bạn sẽ muốn sử dụng virtualenv để giữ riêng biệt với trình thông dịch Python bình thường của bạn. Với bản hack khủng khiếp này tại chỗ, bạn có thể làm

import ctypes 

AwfulHackToGetTheInternedDict = ctypes.pythonapi.AwfulHackToGetTheInternedDict 

AwfulHackToGetTheInternedDict.argtypes =() 
AwfulHackToGetTheInternedDict = ctypes.py_object 

interned = AwfulHackToGetTheInternedDict() 

để lấy nguyên tắc của tất cả các chuỗi nội bộ.


Vì vậy, đó là tùy chọn của bạn hoặc ít nhất, tùy chọn mà tôi đã nghĩ đến. Tôi cũng đã cố gắng buộc GC theo dõi một chuỗi và sau đó interning nó để làm cho dict interned có thể nhìn thấy thông qua GC, nhưng gọi PyObject_GC_Track trên một chuỗi gây ra một lỗi nghiêm trọng, do đó, không hoạt động.

+0

Cảm ơn câu trả lời rất toàn diện. – jchl

0

Vì mục đích của bạn, tôi nghĩ câu trả lời thực sự là sử dụng giải pháp lược tả bộ nhớ mạnh mẽ hơn.

Có một số tùy chọn để thực hiện việc này, chẳng hạn như tùy chọn miễn phí memory_profiler trên pypi.

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