I'm running on: raspbian stretch, python 2.7.13, and WeeWX 3.9.1.

I was noticing a steady increase in memory usage. I narrowed it down to one 
service I had installed. This service binds to the loop event and makes 
over 10 calls to getSql. I updated the service to open and close the 
connection on each loop event. This seems to have stopped the memory 
increase.

Next, I wrote a small program that does the same steps. Create a 
connection, get a cursor, execute a select, fetchone, close the cursor. But 
this isn't exibiting the memory increase.

Next I wrote a wrapper class for the Connection class and subclassed the 
Cursor class, like WeeWX does. Running with these, I am again seeing the 
memory increase.

I don't see how the 'wrapper' classes should matter... Granted at 10+ calls 
per loop, this is aproximately 240 calls a minute - so it would add up 
fast; but I would think others would be seeing something too. I did see 
this thread about the forecast service, 
https://groups.google.com/forum/#!topic/weewx-user/H4GVpoI5l70/discussion 
It looks to make a lot of calls to getSql, but binds to archive, so it 
would happen a lot slower. Not sure if there was any resolution.

I've attached my test program. It can call the sqlite classes directly or 
use the 'wrapper' classes I stole from WeeWx. I may be all wet, but I'm 
seeing something strange in my environment... I'll keep digging.

-rich




 

-- 
You received this message because you are subscribed to the Google Groups 
"weewx-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/weewx-user/3753360b-d4c7-44b3-82ca-a8140514b310%40googlegroups.com.
#!/usr/bin/python2
"""Testing memory"""
import gc
import os
import resource
import sqlite3
import six

VERSION ='0.0.1'
DATABASE = '/home/pi/weewx-weather/archive-replica/weewx.sdb'
STATEMENT = 'SELECT * from archive'
LOOP_AMOUNT = 100000
WRAP_CLASS = True


class Connection(object):
    """ connection """
    def __init__(self, database_name=''):
        """Initialize an instance of Connection."""

        connection = sqlite3.connect(database_name)

        self.connection = connection

    def cursor(self):
        """Return a cursor object."""
        return Cursor(self.connection)

    def close(self):
        """close"""
        self.connection.close()


class Cursor(sqlite3.Cursor):
    """A wrapper around the sqlite cursor object"""

    # The sqlite3 cursor object is very full featured. We need only turn
    # the sqlite exceptions into weedb exceptions.
    def __init__(self, *args, **kwargs):
        sqlite3.Cursor.__init__(self, *args, **kwargs)

    def execute(self, *args, **kwargs):
        """execute"""
        return sqlite3.Cursor.execute(self, *args, **kwargs)

    def fetchone(self):
        """fecth one row"""
        return sqlite3.Cursor.fetchone(self)

    def __enter__(self):
        return self

    def __exit__(self, etyp, einst, etb):  # @UnusedVariable
        # It is not an error to close a sqlite3 cursor multiple times,
        # so there's no reason to guard it with a "try" clause:
        self.close()


def loop(conn):
    """loop"""
    print_mem()

    i = 0
    while i < LOOP_AMOUNT:
        cursor = conn.cursor()

        cursor.execute(STATEMENT)

        result = cursor.fetchone()
        # print(result)

        cursor.close()

        i += 1

    print_mem()
    ngc = gc.collect()
    print("Garbage collected %d objects" % ngc)
    print_mem()

    print("press enter to continue.")
    if six.PY2:
        raw_input()
    else:
        input()

def print_mem():
    """print mem usage"""
    try:
        page_size = resource.getpagesize()
        pid = os.getpid()
        procfile = "/proc/%s/statm" % pid
        try:
            mem_tuple = open(procfile).read().split()
        except (IOError, ):
            return

        # Unpack the tuple:
        (size, resident, share, text, lib, data, dt) = mem_tuple
        mb = 1024 * 1024
        mem_size = float(size) * page_size / mb
        mem_rss = float(resident) * page_size / mb
        mem_share = float(share) * page_size / mb
        print("mem_size: %f mem_rss: %f mem_share: %f" % (mem_size, mem_rss, mem_share))

    except (ValueError, IOError, KeyError) as e:
        print('memory_info failed: %s' % e)

if WRAP_CLASS:
    loop(Connection(DATABASE))
else:
    loop(sqlite3.Connection(DATABASE))

print_mem()

Reply via email to