Экземпляр Google Colab начинается с 12,72 ГБ оперативной памяти.
После создания DataFrame theBigList
было использовано около 9,99 ГБ оперативной памяти.
Это уже довольно неудобная ситуация, поскольку для
Операции Pandas требуют столько же дополнительного пространства, сколько и DataFrame, на котором они работают.
Поэтому мы должны стараться избегать использования даже такого большого объема ОЗУ, если это возможно, и, к счастью, есть простой способ сделать это: просто загрузить каждый файл .npy
и сохранить его данные в базе данных sqlite по одному , даже не создавая theBigList
(см. Ниже).
Однако, если мы используем код, который вы разместили, мы увидим, что использование ОЗУ медленно увеличивается
так как куски theBigList
хранятся в базе данных итеративно.
theBigList
DataFrame хранит строки в массиве NumPy. Но в процессе
передачи строк в базу данных sqlite, строки NumPy
преобразован в строки Python. Это требует дополнительной памяти.
За это Theano tutoral , в котором обсуждается управление внутренней памятью Python,
Для ускорения выделения памяти (и повторного использования) Python использует несколько списков для
маленькие предметы. Каждый список будет содержать объекты аналогичного размера: будет
список для объектов размером от 1 до 8 байт, один для 9 до 16 и т. д. При небольшом объекте
необходимо создать, либо мы повторно используем свободный блок в списке, либо мы выделяем
новый.
... Важным моментом является то, что эти списки никогда не уменьшаются.
Действительно: если предмет (размером х) освобожден (освобожден из-за отсутствия ссылки), его
расположение не возвращается в глобальный пул памяти Python (и тем более в
система), но просто помечается как свободный и добавляется в свободный список предметов размером
Икс. Местоположение мертвого объекта будет использовано повторно, если другой объект совместим
размер нужен. Если доступных мертвых объектов нет, создаются новые.
Если память маленьких объектов никогда не освобождается, то неизбежный вывод таков:
как золотые рыбки, эти маленькие списки объектов только продолжают расти, а не сжимаются,
и что в памяти вашего приложения преобладают самые большие
количество мелких объектов, выделенных в любой заданной точке.
Я полагаю, что это точно описывает поведение, которое вы видите при выполнении этого цикла:
for i in range(0, 588):
theBigList.iloc[i*10000:(i+1)*10000].to_sql(
'CS_table', engine, index=False, if_exists='append')
Несмотря на то, что многие мертвые объекты используются повторно для новых строк, это
Невероятно, если использовать по существу случайные строки, такие как в theBigList
, что дополнительное пространство иногда будет
необходимо, и поэтому объем памяти продолжает расти.
Процесс в конечном итоге достигает предела оперативной памяти Google Colab в 12,72 ГБ, и ядро завершается с ошибкой памяти.
В этом случае самый простой способ избежать использования большого объема памяти - никогда не создавать экземпляр всего DataFrame - вместо этого просто загружайте и обрабатывайте небольшие порции DataFrame по одному:
import numpy as np
import pandas as pd
import matplotlib.cbook as mc
import sqlalchemy as SA
def load_and_store(dbpath):
engine = SA.create_engine("sqlite:///{}".format(dbpath))
for i in range(0, 47):
print('step {}: {}'.format(i, mc.report_memory()))
for letter in list('ABCDEF'):
path = '/content/gdrive/My Drive/SummarizationTempData/CS2Part{}{:02}.npy'.format(letter, i)
comb = np.load(path, allow_pickle=True)
toPD = pd.DataFrame(comb).drop([0, 2, 3], 1).astype(str)
toPD.columns = ['title', 'abstract']
toPD = toPD.loc[toPD['abstract'] != '']
toPD.to_sql('CS_table', engine, index=False, if_exists='append')
dbpath = '/content/gdrive/My Drive/dbfile/CSSummaries.db'
load_and_store(dbpath)
который печатает
step 0: 132545
step 1: 176983
step 2: 178967
step 3: 181527
...
step 43: 190551
step 44: 190423
step 45: 190103
step 46: 190551
Последнее число в каждой строке - это объем памяти, потребляемый процессом, как сообщается
matplotlib.cbook.report_memory . Существует ряд различных мер использования памяти. В Linux mc.report_memory()
сообщает
размер физических страниц образа ядра процесса (включая текст, данные и пространство стека).
Кстати, еще один простой прием управления памятью - использование функций.
Локальные переменные внутри функции освобождаются, когда функция завершается.
Это избавляет вас от необходимости вручную набирать del
и gc.collect()
.