简体   繁体   中英

Python Memory leak using Yocto

I'm running a python script on a raspberry pi that constantly checks on a Yocto button and when it gets pressed it puts data from a different sensor in a database.

a code snippet of what constantly runs is:

#when all set and done run the program
Active = True
while Active:
    if ResponseType == "b":
        while Active:
            try:
                if GetButtonPressed(ResponseValue):
                    DoAllSensors()
                    time.sleep(5)
                else:
                    time.sleep(0.5)
            except KeyboardInterrupt:
                Active = False
            except Exception, e:
                print str(e)
                print "exeption raised continueing after 10seconds"
                time.sleep(10)

the GetButtonPressed(ResponseValue) looks like the following:

def GetButtonPressed(number):
    global buttons
    if ModuleCheck():
        if buttons[number - 1].get_calibratedValue() < 300:
            return True
    else:
        print "module not online"
    return False


def ModuleCheck():
    global moduleb
    return moduleb.isOnline()

I'm not quite sure about what might be going wrong. But it takes about an hour before the RPI runs out of memory.

The memory increases in size constantly and the button is only pressed once every 15 minutes or so.

That already tells me that the problem must be in the code displayed above.

The problem is that the yocto_api.YAPI object will continue to accumulate _Event objects in its _DataEvents dict (a class-wide attribute) until you call YAPI.YHandleEvents . If you're not using the API's callbacks, it's easy to think (I did, for hours) that you don't need to ever call this. The API docs aren't at all clear on the point:

If your program includes significant loops, you may want to include a call to this function to make sure that the library takes care of the information pushed by the modules on the communication channels. This is not strictly necessary, but it may improve the reactivity of the library for the following commands.

I did some playing around with API-level callbacks before I decided to periodically poll the sensors in my own code, and it's possible that some setting got left enabled in them that is causing these events to accumulate. If that's not the case, I can't imagine why they would say calling YHandleEvents is "not strictly necessary," unless they make ARM devices with unlimited RAM in Switzerland.

Here's the magic static method that thou shalt call periodically, no matter what. I'm doing so once every five seconds and that is taking care of the problem without loading down the system at all. API code that would accumulate unwanted events still smells to me, but it's time to move on.

#noinspection PyUnresolvedReferences
@staticmethod
def HandleEvents(errmsgRef=None):
    """
    Maintains the device-to-library communication channel.
    If your program includes significant loops, you may want to include
    a call to this function to make sure that the library takes care of
    the information pushed by the modules on the communication channels.
    This is not strictly necessary, but it may improve the reactivity
    of the library for the following commands.

    This function may signal an error in case there is a communication problem
    while contacting a module.

    @param errmsg : a string passed by reference to receive any error message.

    @return YAPI.SUCCESS when the call succeeds.

    On failure, throws an exception or returns a negative error code.
    """
    errBuffer = ctypes.create_string_buffer(YAPI.YOCTO_ERRMSG_LEN)

    #noinspection PyUnresolvedReferences
    res = YAPI._yapiHandleEvents(errBuffer)
    if YAPI.YISERR(res):
        if errmsgRef is not None:
            #noinspection PyAttributeOutsideInit
            errmsgRef.value = YByte2String(errBuffer.value)
        return res

    while len(YAPI._DataEvents) > 0:
        YAPI.yapiLockFunctionCallBack(errmsgRef)
        if not (len(YAPI._DataEvents)):
            YAPI.yapiUnlockFunctionCallBack(errmsgRef)
            break

        ev = YAPI._DataEvents.pop(0)
        YAPI.yapiUnlockFunctionCallBack(errmsgRef)
        ev.invokeData()
    return YAPI.SUCCESS

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM