Monitor reference count in Python

Source: Internet
Author: User

The problem stems from a problem with the python-CN Mail List: http://groups.google.it/group/python-cn/browse_thread/thread/758891b4342eb2d9/92c12bf6acd667ac

Interestingly, why is the result of SYS. getrefcount (11111111) in python2.4 2, but changed to 3 in python2.5? Even more surprising is that if you run SYS. getrefcount (111111) in the idle of python2.5, you will be surprised to find that, okay, now the result is 2 again. We know that SYS. getrefcount outputs the reference count of an object. Why is the reference count of the same Code and object different in different runtime environments? The reason is that we have a fatal omission.

When examining SYS. getrefcount, we only saw its running results, but in fact there is a more important behind-the-scenes tool-compile. To determine whether compilation affects the reference count of an object, let's look at several examples:

1. In an interactive environment:
Python 2.5 (r25: 51908, May 27 2007, 09:33:26) [MSC v.1310 32 bit (inte
32
Type "help", "Copyright", "Credits" or "License" for more information.

>>> Import sys
>>> SYS. getrefcount (11111111)
3

2. File Execution:
[Ref. py]
Import sys
Print sys. getrefcount (11111111)
The result is as follows:
F:/compile/Python-2.5/pcbuild> Python ref. py
3

3. File Execution (avoiding compilation impact)
[Demo. py]
Import ref
The result is as follows:
F:/compile/Python-2.5/pcbuild> Python demo. py
2

It can be seen that the redundant references are actually contributed by the python compilation process. In the 1 and 2 execution modes, python will activate a compilation action at the beginning; in method 3, the import mechanism will generate a ref. pyC file, so it does not activate the compilation action every time it is executed.

However, we can see that both the interactive environment of python2.5 and the idle environment require compilation, but the output results are different. Why? Well, you need to find the reason from the Python source code. Let's take a look at the output of SYS. getrefcount:
[Sysmodule. C] Static pyobject *
Sys_getrefcount (pyobject * Self, pyobject * Arg)
...{
If (Arg! = NULL & pyint_check (ARG ))...{
If (pyint_aslong (ARG) = 11111111 )...{
Printf ("in sys_getrefcount ");
}
}
Return pyint_fromssize_t (Arg-> ob_refcnt );
}

The original output is the ob_refcnt value in pyobject. In order to understand the change of reference count, we modify the Python source code to monitor every change in reference count, this needs to be modified to the two macros used to change the reference count in Python:
[Object. H] # define py_incref (OP )(
Robert tincref (pyobject *) (OP )),
(OP)-> ob_refcnt ++)

# Define py_decref (OP)
If (Robert decref (pyobject *) (OP )),
-- (OP)-> ob_refcnt! = 0)
_ Py_check_refcnt (OP)
Else
_ Py_dealloc (pyobject *) (OP ))

[Object. C] void Robert tincref (pyobject * OBJ )...{
If (pyint_check (OBJ) & (pyint_aslong (OBJ) = 11111111 ))...{
Long refcnt = obj-> ob_refcnt;
Printf ("increase ref count from % d to % d", refcnt, refcnt + 1 );
}
}

Void Robert tdecref (pyobject * OBJ )...{
If (pyint_check (OBJ) & (pyint_aslong (OBJ) = 11111111 ))...{
Long refcnt = obj-> ob_refcnt;
Printf ("decrease ref count from % d to % d", refcnt, refcnt-1 );
}
}

At the same time, in the reading Point r_object of the PyC file, in the creation point of the integer object pyint_fromlong, the reference count is used to obtain the monitoring code 11111111 added to the point sys_getrefcount. The final output result is as follows:

Execution method 2 (python2.5 interactive environment ):
Create 11111111 in pyint_fromlong!
Increase ref count from 1 to 2 // monitor the results of py_incref
Decrease ref count from 2 to 1 // monitor the results of py_incref
Increase ref count from 1 to 2
Increase ref count from 2 to 3
Increase ref count from 3 to 4
Decrease ref count from 4 to 3
Increase ref count from 3 to 4
Decrease ref count from 4 to 3
Decrease ref count from 3 to 2
Load _ const for 11111111
Increase ref count from 2 to 3
In sys_getrefcount // This line shows that the python virtual machine is currently in the sys_getrefcount function.
Decrease ref count from 3 to 2
3 // This is the output result
Decrease ref count from 2 to 1
Decrease ref count from 1 to 0

Method 3 (load the PyC file ):
Read 11111111 in r_object
Create 11111111 in pyint_fromlong!
Load _ const for 11111111
Increase ref count from 1 to 2
In sys_getrefcount
Decrease ref count from 2 to 1
2
Decrease ref count from 1 to 0

Load_const is a bytecode in Python and is the result of SYS. getrefcount compilation. We also added the monitoring code in the implementation code of the bytecode command.

The compilation process of execution method 2 will adjust the reference count of integer objects frequently, while the action sequence of execution method 3 is clear:
1. the python Virtual Machine reads an integer 11111111 from the PyC file through the r_object function, which activates pyint_fromlong. Here, an integer object is created and the ob_refcnt is set to 1.

2. The print sys. getrefcount (11111111) command in Ref. py finally compiled contains load_const, which increases the reference count of the integer object through py_incref.

In the interactive environment represented by execution method 2, the compilation process has a huge impact on the object reference count, and in idle, this impact is more frequent, let's take a look at the output results when the idle method is executed:
Create 11111111 in pyint_fromlong!
Increase ref count from 1 to 2
Decrease ref count from 2 to 1
Increase ref count from 1 to 2
Increase ref count from 2 to 3
Increase ref count from 3 to 4
Decrease ref count from 4 to 3
Increase ref count from 3 to 4
Decrease ref count from 4 to 3
Decrease ref count from 3 to 2
Decrease ref count from 2 to 1
Create 11111111 in pyint_fromlong!
Increase ref count from 1 to 2
Decrease ref count from 2 to 1
Increase ref count from 1 to 2
Increase ref count from 2 to 3
Increase ref count from 3 to 4
Decrease ref count from 4 to 3
Increase ref count from 3 to 4
Decrease ref count from 4 to 3
Decrease ref count from 3 to 2
Decrease ref count from 2 to 1
Create 11111111 in pyint_fromlong!
Increase ref count from 1 to 2
Decrease ref count from 2 to 1
Increase ref count from 1 to 2
Increase ref count from 2 to 3
Increase ref count from 3 to 4
Decrease ref count from 4 to 3
Increase ref count from 3 to 4
Decrease ref count from 4 to 3
Decrease ref count from 3 to 2
Decrease ref count from 2 to 1
Decrease ref count from 1 to 0
Decrease ref count from 1 to 0
Read 11111111 in r_object
Create 11111111 in pyint_fromlong!
Decrease ref count from 1 to 0
Load _ const for 11111111
Increase ref count from 1 to 2
In sys_getrefcount
Decrease ref count from 2 to 1

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.