Удалить глобальную переменную и освободить память от функции

Мне нужно удалить глобальную переменную и освободить память, которую она использовала, из функции с R, но ни один из вариантов, которые я пробовал, не работает.

Я попробовал функцию rm с параметром envir, а затем gc, но gc не освобождает память. Я также пробовал запускать gc в глобальной среде с помощью eval+envir.

library(data.table)
DT = data.table(col1 = 1:1e6)
cols = paste0('col', 2:100)
for (col in cols){ DT[, col := 1:1e6, with = F] }

rm_and_release <- function(dt){
  dt <- dt[sample(1e6, 9e5, FALSE)]
  print(gc())
  rm(DT, envir = globalenv())

  print(gc())
}

rm_and_release(DT)

Результат следующий

           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   661556  35.4    1168576   62.5   1143443   61.1
Vcells 96303112  734.8   146725516 1119.5 146722586 1119.5
           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   661569  35.4    1168576   62.5   1143443   61.1
Vcells 96303114  734.8   146725516 1119.5 146722586 1119.5

Я ожидал, что второй gc() освободит больше памяти, так как в этот момент есть только один набор данных, потому что глобальное DT было удалено.

Мне нужно освободить оперативную память внутри функции, потому что функция генерирует больше наборов данных, и ей не хватает памяти.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
81
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Используйте list= аргумент rm следующим образом:

library(data.table)
DT = data.table(col1 = 1:1e6)
cols = paste0('col', 2:100)
for (col in cols){ DT[, col := 1:1e6, with = F] }

rm_and_release <- function(dt){
  dt <- dt[sample(1e6, 9e5, FALSE)]
  print(gc())
  rm(list = "DT", envir = globalenv())

  print(gc())
}

rm_and_release(DT)
exists("DT")
## [1] FALSE

Примечание

Вот журнал, когда я запускаю его (в Windows):

> library(data.table)
> gc()
          used (Mb) gc trigger  (Mb) max used  (Mb)
Ncells 1075660 57.5    1899034 101.5  1899034 101.5
Vcells 2609137 20.0   91310117 696.7 99059673 755.8
> DT = data.table(col1 = 1:1e6)
> cols = paste0('col', 2:100)
> for (col in cols){ DT[, col := 1:1e6, with = F] }
There were 50 or more warnings (use warnings() to see the first 50)
> 
> rm_and_release <- function(dt){
+   dt <- dt[sample(1e6, 9e5, FALSE)]
+   print(gc())
+   rm(list = "DT", envir = globalenv())
+ 
+   print(gc())
+ }
> 
> gc()
           used  (Mb) gc trigger  (Mb) max used  (Mb)
Ncells  1076769  57.6    1899034 101.5  1899034 101.5
Vcells 53024698 404.6   91310117 696.7 99059673 755.8
> rm_and_release(DT)
           used  (Mb) gc trigger   (Mb) max used  (Mb)
Ncells  1075902  57.5    1899034  101.5  1899034 101.5
Vcells 97613454 744.8  134081733 1023.0 99059673 755.8
           used  (Mb) gc trigger   (Mb) max used  (Mb)
Ncells  1075901  57.5    1899034  101.5  1899034 101.5
Vcells 97613454 744.8  160978079 1228.2 99059673 755.8
> exists("DT")
[1] FALSE
> gc()
          used (Mb) gc trigger  (Mb) max used  (Mb)
Ncells 1075669 57.5    1899034 101.5  1899034 101.5
Vcells 2613271 20.0  128782463 982.6 99059673 755.8
> ## [1] FALSE

Конечно, это тоже плохо — удалять объект с именем DT независимо от входных данных функции.

Gregor Thomas 29.05.2019 16:46

Плакат не описал свое намерение, а только дал код, и этот код пытается удалить DT независимо от dt, поэтому я просто исправил его, чтобы фактически удалить его, сохранив то, что кажется первоначальным намерением. Если это не его намерение, то вопрос должен быть исправлен.

G. Grothendieck 29.05.2019 16:50

Я попробовал ваш код, но обнаружил, что объект удален, но память не освобождена, оба gc() показывают, что используемая память составляет около 730 МБ. Во втором gc() у нас на одну data.table меньше, поэтому должно быть меньше используемой памяти. Спасибо.

Luis dQ 30.05.2019 17:25

Журнал показан в примечании в конце. Ячейки Ncell и Vcell не изменились, показывая, что какое-либо промежуточное выделение памяти было освобождено.

G. Grothendieck 30.05.2019 17:42

Спасибо @ Г. Гротендик. Однако память не освобождается до тех пор, пока функция не завершится, мне нужно освободить ее раньше, потому что моя реальная функция использует больше памяти в конце и заканчивается. Я не уверен, что мои намерения ясны. Я опубликовал ответ (не слишком красивый), где память освобождается внутри функции.

Luis dQ 31.05.2019 10:11
Ответ принят как подходящий

Я нашел код, который работает

library(data.table)
DT = data.table(col1 = 1:1e6)
cols = paste0('col', 2:100)
for (col in cols){ DT[, col := 1:1e6, with = F] }

rm_and_release <- function(){
  dt <- copy(DT)
  dt <- dt[sample(1e6, 9e5, FALSE)]
  print(gc())
  rm(DT, envir = globalenv())

  print(gc())
}

rm_and_release()

Это приводит к

           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   865272  46.3    1442291   77.1   1280599   68.4
Vcells 96733883 738.1  167167064 1275.4 147681076 1126.8
           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   865173  46.3    1442291   77.1   1280599   68.4
Vcells 46731629 356.6  133733651 1020.4 147681076 1126.8

Я думаю, что очень некрасиво не вставлять DT в качестве аргумента функции, но, по крайней мере, в этом сценарии память уменьшена с 738 МБ до 356 МБ, что имеет решающее значение для того, что я делаю.

Другие вопросы по теме