2016-06-14 27 views
5

düzenleme:Python, neden mmap.move() belleği doldurur?

def delete_bytes(fobj, offset, size): 
    fobj.seek(0, 2) 
    filesize = fobj.tell() 
    move_size = filesize - offset - size 

    fobj.flush() 
    file_map = mmap.mmap(fobj.fileno(), filesize) 
    file_map.move(offset, offset + size, move_size) 
    file_map.close() 

    fobj.truncate(filesize - size) 
    fobj.flush() 

Bu süper hızlı çalışır, ancak ben bunu çalıştırdığınızda: Ben ofset belli bir dosyadan bayt kaldırmak için mmap'e kullanan bir işleve sahip Win10 ve python 3.5

kullanma Çok sayıda dosya, bellek hızlı bir şekilde doldurur ve sistemim yanıt vermemeye başlar.

Bazı deneylerden sonra, move() yönteminin buradaki suçlu olduğunu ve özellikle de taşınan veri miktarını (move_size) buldum. Kullanılan bellek miktarı, mmap.move() ile taşınan toplam veri miktarına eşittir. Her bir ~ 30 MB'lık taşınan 100 dosyam varsa, bellek ~ 3GB ile doldurulur.

Taşınan veriler neden bellekte bırakılmıyor? hiçbir etkisi Denedim

şeyler:

  • işlevi sonunda gc.collect() arayarak. Küçük parçalar halinde hareket etmek için işlevi yeniden yazmak
  • .
+0

Hangi işletim sistemini kullanıyorsunuz? Python sürümü de. – wind85

+0

Ayrıca, belleğin python işleminiz mi yoksa İşletim Sistemi mi tarafından kullanıldığını kontrol edebilir misiniz? – Leon

+0

Üzgünüz, bahsetmeyi unuttum: Win10 ve python 3.5'dayım. Belleğin python veya işletim sistemi tarafından kullanıldığını nasıl kontrol ederim? – mahkitah

cevap

1

Bu, 'un çalışması gerekir gibi görünüyor. Mmapmodule.c kaynak kodunda #ifdef MS_WINDOWS bir şüpheli bit buldum. Tüm kurulum argümanları ayrıştırmak sonra Özellikle, kod sonra yapar:

sizin temel dosya nesne yönettiği "dosyanın sonuna" dan ofset sonra "dosyasının başlangıç" ve orada bırakır hamle
if (fileno != -1 && fileno != 0) { 
    /* Ensure that fileno is within the CRT's valid range */ 
    if (_PyVerify_fd(fileno) == 0) { 
     PyErr_SetFromErrno(PyExc_OSError); 
     return NULL; 
    } 
    fh = (HANDLE)_get_osfhandle(fileno); 
    if (fh==(HANDLE)-1) { 
     PyErr_SetFromErrno(PyExc_OSError); 
     return NULL; 
    } 
    /* Win9x appears to need us seeked to zero */ 
    lseek(fileno, 0, SEEK_SET); 
} 

. Bu, 'un'un hiçbir şeyi kırmaması gerektiğini düşünüyor, ancak dosyayı eşlemek için mmap.mmap numaralı telefonu aramadan önce kendi aramaya başlamak için arama yapmaya değiyor olabilirsiniz.

(aşağıda her şey ters, ama o yorumların olduğunu çünkü kalan budur.) Genel olarak


, mmap() kullandıktan sonra, eşleme geri almak için munmap() kullanmalıdır. Basitçe dosya tanıtıcısını kapatmanın bir etkisi yoktur. Linux documentation aramalar açıkça bunu:

munmap()
munmap() sistem çağrısı belirtilen adres aralığı için eşleştirmeleri siler ve geçersiz bellek referansları üretmeye yönelik aralığında adreslerine ayrıca başvuruları neden olur. İşlem sonlandırıldığında bölge otomatik olarak eşlenmez. Öte yandan, dosya tanıtıcısını kapatmak bölgeyi unmap etmiyor.

(BSD belgeler Windows burada Unix benzeri sistemlerden farklı davranabilir. Benzerdir, ama ne görüyoruz onlar da aynı şekilde çalışır düşündürmektedir.) Maalesef

, Python'un mmap modülü bağlama yapmaz munmap sistem çağrısı (ya da mprotect), en azından hem 2.7.11 hem de 3.4.4'den itibaren. Bir geçici çözüm olarak, ctypes modülünü kullanabilirsiniz.Örnek için this question'a bakın (reboot'u çağırır, ancak aynı teknik tüm C kütüphanesi işlevleri için çalışır). Ya da, biraz daha hoş bir yöntem için, sarıcıları 'a yazabilirsiniz.

+0

mmap.close() işlevi 'unmap()' yerine getirmiyor mu? – Leon

+1

'mmap.close()' 'UnmapViewOfFile' (windows) veya' munmap' (unix) (python 3.4, mmapmodule.c) işlevini çağırır. –

+0

Eşlemenin kendisi sorun değil. Eğer satırı mmap.move() ile kaldırırsam veya başka bir yöntemle (mmap.resize() 'gibi) değiştirirsem hiç sorun olmaz. – mahkitah