退出时内存损坏(或愚蠢的用户错误)

时间:2018-05-28 22:43:52

标签: python python-3.5

我遇到一个问题,即导入python模块的对象被破坏,但只有在显式调用sys.exit()之后才会出现问题。这也是间歇性的。除了“标准”pyusb模块之外,我已经删除了大部分代码(我已经使用了最新版本)。实际上很少发生。

如果程序调用sys.exit(),则某些对象ID将更改为垃圾值。如果我把它留下来就没有错误!

这真的是Python中的一个错误吗?这似乎不太可能。我做错了什么?

=====主程序“bug_happens.py”

#!/usr/bin/python3

import sys

import usbtmc

scope = usbtmc.Instrument()
print('in Main')
print('   id of usbtmc.usb: 0x{:x}'.format(id(usbtmc.usb)))
print('   id of usbtmc.usb.util: 0x{:x}'.format(id(usbtmc.usb.util)))
print('   id of usbtmc.usb.util.dispose_resources: 0x{:x}'.format(id(usbtmc.usb.util.dispose_resources)))
print()

print('calling Exit()')
sys.exit()

=====非常剥离了usbtmc模块

"""
****** Very stripped down partial Version for debugging a memory corruption issue ******

Python USBTMC driver

Copyright (c) 2012-2017 Alex Forencich

...
"""

import usb.util

class Instrument(object):
    def __init__(self, *args, **kwargs):

        self.connected = False

        print('usbtmc.Instrument created 0x{:x}'.format(id(self)))
        print('   id of usb: 0x{:x}'.format(id(usb)))
        print('   id of usb.util: 0x{:x}'.format(id(usb.util)))
        print('   id of usb.util.dispose_resources: 0x{:x}'.format(id(usb.util.dispose_resources)))
        print()

    def __del__(self):
        print('usbtmc.Instrument.__del__() called for 0x{:x}'.format(id(self)))
        print('   id of usb: 0x{:x}'.format(id(usb)))
        print('   id of usb.util: 0x{:x}'.format(id(usb.util)))
        print('   id of usb.util.dispose_resources: 0x{:x}'.format(id(usb.util.dispose_resources)))
        print('   end of usbtmc.Instrument.__del__()')
        print()

=============================================== =======

=====很多时候这很好用:

usbtmc.Instrument created 0x7fee5775d9b0
   id of usb: 0x7fee562800e8
   id of usb.util: 0x7fee562247c8
   id of usb.util.dispose_resources: 0x7fee561ad048

in Main
   id of usbtmc.usb: 0x7fee562800e8
   id of usbtmc.usb.util: 0x7fee562247c8
   id of usbtmc.usb.util.dispose_resources: 0x7fee561ad048

calling Exit()
usbtmc.Instrument.__del__() called for 0x7fee5775d9b0
   id of usb: 0x7fee562800e8
   id of usb.util: 0x7fee562247c8
   id of usb.util.dispose_resources: 0x7fee561ad048
   end of usbtmc.Instrument.__del__()

=============================================== =======

=====大约50%的时间是这样的:

usbtmc.Instrument created 0x7fec34b829b0
   id of usb: 0x7fec336c3278
   id of usb.util: 0x7fec335dbb88
   id of usb.util.dispose_resources: 0x7fec335e5048

in Main
   id of usbtmc.usb: 0x7fec336c3278
   id of usbtmc.usb.util: 0x7fec335dbb88
   id of usbtmc.usb.util.dispose_resources: 0x7fec335e5048

calling Exit()
usbtmc.Instrument.__del__() called for 0x7fec34b829b0
   id of usb: 0xa40060
Exception ignored in: <bound method Instrument.__del__ of <usbtmc.Instrument object at 0x7fec34b829b0>>
Traceback (most recent call last):
  File "/home/don/Electronics/Projects/HF_Meas/Scope_SA/Bug_usb_close/usbtmc.py", line 27, in __del__
AttributeError: 'NoneType' object has no attribute 'util'

=============================================== =======

=====偶尔会这样做:

usbtmc.Instrument created 0x7ff75968c9b0
   id of usb: 0x7ff7581af0e8
   id of usb.util: 0x7ff7581537c8
   id of usb.util.dispose_resources: 0x7ff7580dc048

in Main
   id of usbtmc.usb: 0x7ff7581af0e8
   id of usbtmc.usb.util: 0x7ff7581537c8
   id of usbtmc.usb.util.dispose_resources: 0x7ff7580dc048

calling Exit()
usbtmc.Instrument.__del__() called for 0x7ff75968c9b0
   id of usb: 0x7ff7581af0e8
   id of usb.util: 0xa40060
Exception ignored in: <bound method Instrument.__del__ of <usbtmc.Instrument object at 0x7ff75968c9b0>>
Traceback (most recent call last):
  File "/home/don/Electronics/Projects/HF_Meas/Scope_SA/Bug_usb_close/usbtmc.py", line 28, in __del__
AttributeError: 'NoneType' object has no attribute 'dispose_resources'

使用python3 3.5.1-3在Mint 18.3系统上运行 和python3-usb 1.0.0~b2-2或pyusb-1.0.2的新git pull

1 个答案:

答案 0 :(得分:1)

当Python解释器退出时,运行时正在被拆除,对象删除的顺序不是你可以依赖的。实际上,甚至不能保证在解释器退出时会调用__del__()方法。

自定义__del__需要访问的对象(包括其他模块)可能已被删除或设置为None,这将导致您在此处看到的异常(&# 39; NoneType&#39;对象没有属性...)

这不是真正的内存损坏&#34;,它只是为Instrument类编写的糟糕代码。应使用__enter____exit__管理任何必要的设置/拆卸上下文,因为__del__不适用于此目的。所以,这个问题或多或少是Instrument中的一个错误。通过利用记录here

的数据模型保证,可以改进此代码
  

Python保证在删除其他全局变量之前,从其模块中删除名称以单个下划线开头的全局变量;如果不存在对此类全局变量的其他引用,这可能有助于确保在调用__del__()方法时导入的模块仍然可用。