簡體   English   中英

Python內存不足(使用后綴樹)

[英]Python Running out of Memory (Using Suffix Trees)

我在使用某些代碼時遇到了麻煩。 請記住,我是一個糟糕的程序員,所以我的解決方案可能不是很雄辯(這可能是我內存不足的原因-我有4 GB,並且腳本會慢慢填滿它)。

這是問題所在。 我的目錄中大約有3500個文件。 每個文件由一行組成,該行可以有相對較少的字符或沒有空格的許多字符(最小的文件為200字節,最大的文件為1.3兆字節)。 我想做的是一次在設置長度的兩個文件之間找到一個公共子字符串(在下面的代碼中是13個字符)。 我一次要執行兩個操作,因為我不是在所有這些操作中都尋找一個通用的子字符串,而是在兩個文件進行比較之前將它們組合在一起。 即,文件之間設置長度的任何公共子字符串,而不是所有文件公共的子字符串。

我使用了一個后綴樹模塊,該模塊包裝了C實現( 在此處 )。 首先,我列出目錄中的所有文件,然后查找兩個文件的組合,以便覆蓋所有組合,然后一次將兩個文件傳遞到后綴樹,然后查找常見子串的序列。

但是,我真的不知道為什么它會慢慢耗盡內存。 我希望我們可以對代碼進行修改,以便以某種方式清除內存中未使用的內容? 顯然,要處理3500個文件將花費很長時間,但是我希望無需增量填充4 GB內存就可以做到。 任何幫助將不勝感激! 這是到目前為止我得到的代碼:

from suffix_tree import GeneralisedSuffixTree
from itertools import combinations
import glob, hashlib, os

alist = open('tmp.adjlist', 'w')

def read_f(f):
    f = open(f, "r")
    s = str(f.readlines())
    f.close()
    return s

def read_gs(a,b):
    s1 = read_f(a)
    s2 = read_f(b)
    print str(a) + ":" + str(hashlib.md5(s1).hexdigest()) + " --- " + str(b) + ":" + str(hashlib.md5(s2).hexdigest())
    return [s1,s2]

def build_tree(s):
    hlist = []

    stree = GeneralisedSuffixTree(s)

    for shared in stree.sharedSubstrings(13):
        for seq,start,stop in shared:
            hlist.append(hashlib.md5(stree.sequences[seq]).hexdigest())
        hlist = list(set(hlist))
        for h in hlist:
            alist.write(str(h) + " ")
        alist.write('\n')

glist = []

for g in glob.glob("*.g"):
    glist.append(g)

for a,b in list(combinations(glist, 2)):
    s = read_gs(a,b)
    build_tree(s)

alist.close()

os.system("uniq tmp.adjlist network.adjlist && rm tmp.adjlist")

更新1

這是更新的代碼。 我添加了Pyrce提出的建議。 但是,在jogojapan確定了C代碼中的內存泄漏並考慮到它超出了我的專業知識之后,我最終選擇了一種慢得多的方法。 如果有人對此領域有知識,我真的很想知道如何修改C代碼以解決內存泄漏或釋放函數,因為我認為Python的C后綴樹綁定非常有價值。 在沒有后綴樹的情況下,通過此腳本運行數據可能需要幾天的時間,因此我絕對願意看看是否有人有創造性的解決方案!

from itertools import combinations
import glob, hashlib, os

def read_f(f):
    with open(f, "r") as openf:
        s = str(openf.readlines())
    return s

def read_gs(a,b):
    s1 = read_f(a)
    s2 = read_f(b)
    print str(a) + ":" + str(hashlib.md5(s1).hexdigest()) + " --- " + str(b) + ":" + str(hashlib.md5(s2).hexdigest())
    return [s1,s2]

def lcs(S1, S2):
    M = [[0]*(1+len(S2)) for i in xrange(1+len(S1))]
    longest, x_longest = 0, 0
    for x in xrange(1,1+len(S1)):
        for y in xrange(1,1+len(S2)):
            if S1[x-1] == S2[y-1]:
                M[x][y] = M[x-1][y-1] + 1
                if M[x][y]>longest:
                    longest = M[x][y]
                    x_longest  = x
            else:
                M[x][y] = 0
    return S1[x_longest-longest: x_longest]

glist = glob.glob("*.g")

for a,b in combinations(glist, 2):
    s = read_gs(a,b)
    p = lcs(s[0],s[1])
    if p != "" and len(p) >= 13:
        with open("tmp.adjlist", "a") as openf:
            openf.write(hashlib.md5(s[1]).hexdigest() + " " + hashlib.md5(s[0]).hexdigest() + "\n")

os.system("uniq tmp.adjlist network.adjlist && rm tmp.adjlist")

我完全有信心在您使用的后綴樹包內部存在內存泄漏。

證據1:在valgrind中運行python,然后運行此簡單的Python腳本

from suffix_trees import SuffixTree
t = SuffixTree("mississippi")
t = None

報告了此泄漏:

==8800== 1,413 (32 direct, 1,381 indirect) bytes in 1 blocks are definitely lost in loss record 1,265 of 1,374
==8800==    at 0x4A0884D: malloc (vg_replace_malloc.c:263)
==8800==    by 0xBE70AEC: make_helper (suffix_tree.c:193)
==8800==    by 0xBE704B2: SuffixTree_init (python_bindings.c:240)
==8800==    by 0x3F98C9867B: ??? (in /usr/lib64/libpython2.7.so.1.0)
==8800==    by 0x3F98C49A7D: PyObject_Call (in /usr/lib64/libpython2.7.so.1.0)
==8800==    by 0x3F98CD71D6: PyEval_CallObjectWithKeywords (in /usr/lib64/libpython2.7.so.1.0)
==8800==    by 0x3F98C5EB45: ??? (in /usr/lib64/libpython2.7.so.1.0)
==8800==    by 0x3F98C49A7D: PyObject_Call (in /usr/lib64/libpython2.7.so.1.0)
==8800==    by 0x3F98CD93F2: PyEval_EvalFrameEx (in /usr/lib64/libpython2.7.so.1.0)
==8800==    by 0x3F98CDDB2E: PyEval_EvalCodeEx (in /usr/lib64/libpython2.7.so.1.0)
==8800==    by 0x3F98C6D7B5: ??? (in /usr/lib64/libpython2.7.so.1.0)
==8800==    by 0x3F98C49A7D: PyObject_Call (in /usr/lib64/libpython2.7.so.1.0)

證據2:查看suffix_tree.c和python_bindings.c中的代碼時,您會找到make_helper()函數,該函數為后綴樹分配內存(使用malloc ),但是在其中的任何地方都沒有一個free 。碼。 我專門研究了為python_bindings中定義的Python類型定義的分配和釋放函數,但找不到針對樹對象的任何函數。 節點對象有一個,但是只釋放對象的Python包裝器部分,而不釋放C中的基礎結構。

證據3: python_bindings.c中Python對象的數據類型定義附有一個有說服力的注釋:

/* FIXME: deallocation of this guy! */
static PyTypeObject SuffixTreeType = {
    PyObject_HEAD_INIT(NULL)
    .tp_name      = "_suffix_tree.SuffixTree",
    /* ... */
    .tp_new       = SuffixTree_new,
};

建議:您可能要聯系軟件包的作者,並讓他們知道問題所在。 根據網頁上的信息,他們已經在解決以下問題:理想情況下,樹本身與其包含的節點對象之間應該存在循環依賴關系-這是一個相關問題,並且可能是該程序的原因當前不執行任何重新分配。

由於您可能不需要節點到樹的依賴關系,因此您還可以通過在python_bindings.c中的樹對象定義中添加釋放函數來應用自己的修復程序。

我不是100%肯定原始代碼的邏輯是否確實符合您的預期-肯定有一個不斷增長的清單,我認為您打算重置。 變量hlist一直被添加,而不會在“共享”上循環。 使該循環局部化可解決該問題。 另外,您無需列出列表的集合,只需使用一個集合開始並對該集合進行迭代。 我建議更多地了解Python中的可迭代對象-其中幾乎所有Python數據保存對象都是(可迭代的)。 基本上,除非需要特定的順序,否則不需要列出()這些對象,即使那樣,通常也只需要使用sort()。

下面的build_tree解決了這些問題,應顯着減少內存占用-並希望阻止它的增長。

def build_tree(s):
    stree = GeneralisedSuffixTree(s)

    for shared in stree.sharedSubstrings(13):
        hset = set()
        for seq,start,stop in shared:
            hset.add(hashlib.md5(stree.sequences[seq]).hexdigest())

        for h in hset:
            alist.write(str(h) + " ")
        alist.write('\n')
        # Request cleanup on finished data
        del hset
    # Request cleanup on finished data
    del stree

在使用文件時,也請使用'with'關鍵字-它確保完成后文件將被關閉-在這種情況下,如果引發異常,則打開/關閉可能會使以后的代碼庫受阻。

def read_f(f):
    with open(f, "r") as openf:
        s = str(openf.readlines())
    return s

正如我上面提到的,刪除返回的所有變量的list()包裝器-它們已經可迭代了,對它們進行list()可能會消耗大量內存/運行時間來存儲大型可迭代項。 即:

for a,b in list(combinations(glist, 2)):

應該:

for a,b in combinations(glist, 2):

glist = []
for g in glob.glob("*.g"):
    glist.append(g)

應該變成:

glist = glob.glob("*.g")

這些更改應該會有所幫助,讓我知道您是否仍然用完內存,但是現在隨着列表的增加,內存使用量應該只會增加-一旦列表變大就會刷新。 C代碼也可能發生內存泄漏(我沒有使用過該庫),在這種情況下,您還將遇到內存問題。 但是您的Python代碼更有可能是罪魁禍首。

注意:我沒有測試我在此處發布的建議更改,因此在這里和那里可能存在較小的語法錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM