2012-10-25 26 views
5

Tôi chỉ đang cố gắng hiểu cách xử lý số lượng tham chiếu khi sử dụng API C C.API C C Python, Số lượng tham chiếu cao cho Đối tượng mới

Tôi muốn gọi một hàm Python trong C++, như thế này:

PyObject* script; 
PyObject* scriptRun; 
PyObject* scriptResult; 

// import module 
script = PyImport_ImportModule("pythonScript"); 
// get function objects 
scriptRun = PyObject_GetAttrString(script, "run"); 
// call function without/empty arguments 
scriptResult = PyObject_CallFunctionObjArgs(scriptRun, NULL); 

if (scriptResult == NULL) 
    cout << "scriptResult = null" << endl; 
else 
    cout << "scriptResult != null" << endl; 

cout << "print reference count: " << scriptResult->ob_refcnt << endl; 

Các Python mã trong pythonScript.py rất đơn giản:

def run(): 
    return 1 

Các tài liệu về "PyObject_CallFunctionObjArgs" nói rằng bạn nhận được một tham chiếu mới là giá trị trả về. Vì vậy, tôi mong chờ "scriptResult" để có một số tài liệu tham khảo của 1. Tuy nhiên, sản lượng là:

scriptResult != null 
print reference count: 72 

Hơn nữa tôi mong chờ một rò rỉ bộ nhớ nếu tôi làm điều này trong một vòng lặp mà không làm giảm tính tham khảo. Tuy nhiên điều này dường như không xảy ra.

Ai đó có thể giúp tôi hiểu không?

Trân trọng!

+0

Câu hỏi tiếp theo: Cảm ơn @ecatmur và @KayZhu Tôi giờ đã hiểu tại sao không có rò rỉ bộ nhớ. Tuy nhiên nếu tôi chạy mã này trong một vòng lặp dài os hoàn thành của tôi nghiền nát anyway. Số tham chiếu đến '1' đang tăng lên, mỗi lần lặp lại, nhưng tôi không thấy lý do tại sao điều này sẽ gây ra lỗi hệ thống. – user1774143

+0

Bạn đang lặp cho đến khi chu kỳ 'ob_refcnt' quay lại 0? Số lượng tham chiếu của 1 biến động rất nhiều. Khi bạn quấn xung quanh 0, các hoạt động bình thường có thể 'Py_DECREF' thành 0 và khiến' int' 1 bị deallocated, theo sau bởi một segfault. Hãy thử nó với một ít int interned 'int' như 13. – eryksun

+0

Ít nhất, tôi thậm chí không looping cho đến khi 'sys.maxint' (đó là '9223372036854775807' trên hệ thống của tôi). Hôm nay có vẻ như tôi không thể tạo lại lỗi và tôi đoán tôi nên ngừng cố gắng quay máy tính để bàn làm việc của mình xuống. Cảm ơn bạn đã giúp đỡ! – user1774143

Trả lời

2

ecatmur là đúng, số và chuỗi được thực hiện bằng Python, vì vậy thay vào đó bạn có thể thử với đối tượng object() đơn giản.

Một bản demo đơn giản với gc:

import gc 


def run(): 
    return 1 

s = run() 
print len(gc.get_referrers(s)) # prints a rather big number, 41 in my case 

obj = object() 
print len(gc.get_referrers(obj)) # prints 1 

lst = [obj] 
print len(gc.get_referrers(obj)) # prints 2 

lst = [] 
print len(gc.get_referrers(obj)) # prints 1 again 

Một chút hơn: khi CPython tạo ra một đối tượng mới, mà họ gọi là C vĩ mô _Py_NewReference để khởi tạo đếm tham chiếu đến 1. Sau đó, sử dụng Py_INCREF(op)Py_DECREF(op) để tăng và giảm số lượng tham chiếu.

+0

Cảm ơn bạn! Tuy nhiên, nếu tôi thay thế s bằng một số như 123456.7565 tôi vẫn nhận được 1 liên kết giới thiệu. Nếu tôi làm điều đó trong mã python của tôi được gọi là mã C + + của tôi, tôi vẫn nhận được 2. Bất kỳ ý tưởng tại sao điều này có thể được? – user1774143

+1

@ user1774143: Đang trả về '123456.7565' từ hàm' run() '? Nếu tham chiếu thứ 2 là tuple của các đối tượng mã của các hằng số: 'run .__ code __. Co_consts'. – eryksun

+0

Tôi hiểu rồi. Trong tuple này, tất cả các hằng số trong phương thức được lưu trữ vì vậy tôi có một tham chiếu bổ sung ở đây. Cảm ơn! – user1774143

4

Sự nhầm lẫn là số nguyên nhỏ (cũng True, False, None, chuỗi ký tự duy nhất, vv) là thực tập nội trú ("is" operator behaves unexpectedly with integers), có nghĩa là bất cứ nơi nào chúng được sử dụng hoặc thu được trong một chương trình thời gian chạy sẽ cố gắng sử dụng các trường hợp đối tượng giống nhau:

>>> 1 is 1 
True 
>>> 1 + 1 is 2 
True 
>>> 1000 + 1 is 1001 
False 

Điều này có nghĩa rằng khi bạn viết return 1, bạn đang trở về một thể hiện int đối tượng đã tồn tại với (như bạn đã nhìn thấy) một số tài liệu tham khảo đáng kể. Bởi vì cùng một trường hợp được sử dụng ở nơi khác, không dereference nó sẽ không dẫn đến rò rỉ bộ nhớ.

Nếu bạn thay đổi tập lệnh thành return 1001 hoặc return object() thì bạn sẽ thấy số lượng tham chiếu ban đầu là 1 và rò rỉ bộ nhớ.

+0

Cảm ơn bạn đã trả lời nhanh, tôi không biết về số nguyên nhỏ! Tuy nhiên, nếu tôi thay đổi giá trị trả về thành 1001 hoặc một số giá trị vui khác, tôi vẫn nhận được số tham chiếu là 2 thay vì 1. – user1774143

+0

thì giờ tôi thấy rằng đối tượng trả về() số đếm tham chiếu thực tế là 1! – user1774143

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