Trucos para administrar la memoria disponible en una sesión R

¿Qué trucos usa la gente para administrar la memoria disponible de una sesión R interactiva? Utilizo las funciones siguientes [basadas en las publicaciones de Petr Pikal y David Hinds en la lista de ayuda de r en 2004] para enumerar (y / u ordenar) los objetos más grandes y ocasionalmente rm() algunos de ellos. Pero, con mucho, la solución más efectiva fue … ejecutar bajo Linux de 64 bits con amplia memoria.

¿Algún otro truco que la gente quiera compartir? Una por publicación, por favor.

 # improved list of objects .ls.objects <- function (pos = 1, pattern, order.by, decreasing=FALSE, head=FALSE, n=5) { napply <- function(names, fn) sapply(names, function(x) fn(get(x, pos = pos))) names <- ls(pos = pos, pattern = pattern) obj.class <- napply(names, function(x) as.character(class(x))[1]) obj.mode <- napply(names, mode) obj.type <- ifelse(is.na(obj.class), obj.mode, obj.class) obj.size <- napply(names, object.size) obj.dim <- t(napply(names, function(x) as.numeric(dim(x))[1:2])) vec <- is.na(obj.dim)[, 1] & (obj.type != "function") obj.dim[vec, 1] <- napply(names, length)[vec] out <- data.frame(obj.type, obj.size, obj.dim) names(out) <- c("Type", "Size", "Rows", "Columns") if (!missing(order.by)) out <- out[order(out[[order.by]], decreasing=decreasing), ] if (head) out <- head(out, n) out } # shorthand lsos <- function(..., n=10) { .ls.objects(..., order.by="Size", decreasing=TRUE, head=TRUE, n=n) } 

Asegúrese de registrar su trabajo en un script reproducible. De vez en cuando, vuelva a abrir R, luego source() su secuencia de comandos. Limpiará todo lo que ya no esté usando y, como beneficio adicional, habrá probado su código.

Yo uso el paquete data.table Con su operador := puedes:

  • Agregar columnas por referencia
  • Modificar subconjuntos de columnas existentes por referencia y por grupo por referencia
  • Eliminar columnas por referencia

Ninguna de estas operaciones copia la data.table (potencialmente grande), ni siquiera una vez.

  • La agregación también es particularmente rápida porque data.table usa mucha menos memoria de trabajo.

Enlaces relacionados :

  • Noticias de data.table, London R presentation, 2012
  • ¿Cuándo debería usar el operador := en data.table?

¡Vi esto en una publicación de Twitter y creo que es una función increíble de Dirk! Después de la respuesta de JD Long, haría esto para una lectura fácil de usar:

 # improved list of objects .ls.objects < - function (pos = 1, pattern, order.by, decreasing=FALSE, head=FALSE, n=5) { napply <- function(names, fn) sapply(names, function(x) fn(get(x, pos = pos))) names <- ls(pos = pos, pattern = pattern) obj.class <- napply(names, function(x) as.character(class(x))[1]) obj.mode <- napply(names, mode) obj.type <- ifelse(is.na(obj.class), obj.mode, obj.class) obj.prettysize <- napply(names, function(x) { format(utils::object.size(x), units = "auto") }) obj.size <- napply(names, object.size) obj.dim <- t(napply(names, function(x) as.numeric(dim(x))[1:2])) vec <- is.na(obj.dim)[, 1] & (obj.type != "function") obj.dim[vec, 1] <- napply(names, length)[vec] out <- data.frame(obj.type, obj.size, obj.prettysize, obj.dim) names(out) <- c("Type", "Size", "PrettySize", "Length/Rows", "Columns") if (!missing(order.by)) out <- out[order(out[[order.by]], decreasing=decreasing), ] if (head) out <- head(out, n) out } # shorthand lsos <- function(..., n=10) { .ls.objects(..., order.by="Size", decreasing=TRUE, head=TRUE, n=n) } lsos() 

Lo que resulta en algo como lo siguiente:

  Type Size PrettySize Length/Rows Columns pca.res PCA 790128 771.6 Kb 7 NA DF data.frame 271040 264.7 Kb 669 50 factor.AgeGender factanal 12888 12.6 Kb 12 NA dates data.frame 9016 8.8 Kb 669 2 sd. numeric 3808 3.7 Kb 51 NA napply function 2256 2.2 Kb NA NA lsos function 1944 1.9 Kb NA NA load loadings 1768 1.7 Kb 12 2 ind.sup integer 448 448 bytes 102 NA x character 96 96 bytes 1 NA 

NOTA: La parte principal que agregué fue (nuevamente, adaptada de la respuesta de JD):

 obj.prettysize < - napply(names, function(x) { print(object.size(x), units = "auto") }) 

Me encanta el guión de .ls.objects () de Dirk, pero seguí entrecerrando los ojos para contar los caracteres en la columna de tamaño. Así que hice algunos feos hacks para hacerlo presente con un bonito formato para el tamaño:

 .ls.objects < - function (pos = 1, pattern, order.by, decreasing=FALSE, head=FALSE, n=5) { napply <- function(names, fn) sapply(names, function(x) fn(get(x, pos = pos))) names <- ls(pos = pos, pattern = pattern) obj.class <- napply(names, function(x) as.character(class(x))[1]) obj.mode <- napply(names, mode) obj.type <- ifelse(is.na(obj.class), obj.mode, obj.class) obj.size <- napply(names, object.size) obj.prettysize <- sapply(obj.size, function(r) prettyNum(r, big.mark = ",") ) obj.dim <- t(napply(names, function(x) as.numeric(dim(x))[1:2])) vec <- is.na(obj.dim)[, 1] & (obj.type != "function") obj.dim[vec, 1] <- napply(names, length)[vec] out <- data.frame(obj.type, obj.size,obj.prettysize, obj.dim) names(out) <- c("Type", "Size", "PrettySize", "Rows", "Columns") if (!missing(order.by)) out <- out[order(out[[order.by]], decreasing=decreasing), ] out <- out[c("Type", "PrettySize", "Rows", "Columns")] names(out) <- c("Type", "Size", "Rows", "Columns") if (head) out <- head(out, n) out } 

Hago un uso agresivo del parámetro de subset con la selección de solo las variables requeridas al pasar dataframes a los data= argumento de las funciones de regresión. Resulta en algunos errores si olvido agregar variables tanto a la fórmula como a la select= vector, pero aún ahorra mucho tiempo debido a la disminución de la copia de objetos y reduce significativamente la huella de memoria. Digamos que tengo 4 millones de registros con 110 variables (y lo hago). Ejemplo:

 # library(rms); library(Hmisc) for the cph,and rcs functions Mayo.PrCr.rbc.mdl < - cph(formula = Surv(surv.yr, death) ~ age + Sex + nsmkr + rcs(Mayo, 4) + rcs(PrCr.rat, 3) + rbc.cat * Sex, data = subset(set1HLI, gdlab2 & HIVfinal == "Negative", select = c("surv.yr", "death", "PrCr.rat", "Mayo", "age", "Sex", "nsmkr", "rbc.cat") ) ) 

Para establecer el contexto y la estrategia: la variable gdlab2 es un vector lógico que se construyó para sujetos en un conjunto de datos que tenían todos los valores normales o casi normales para un conjunto de pruebas de laboratorio y HIVfinal era un vector de caracteres que resumía las pruebas preliminares y confirmatorias para el VIH

Ese es un buen truco

Otra sugerencia es utilizar objetos con memoria eficiente siempre que sea posible: por ejemplo, use una matriz en lugar de un dataframe.

Esto realmente no aborda la administración de la memoria, pero una función importante que no es ampliamente conocida es memory.limit (). Puede boost el valor predeterminado utilizando este comando, memory.limit (size = 2500), donde el tamaño está en MB. Como mencionó Dirk, necesitas usar 64 bits para aprovechar esto realmente.

Me gusta bastante la función de objetos mejorados desarrollada por Dirk. Sin embargo, la mayor parte del tiempo, un resultado más básico con el nombre y el tamaño del objeto es suficiente para mí. Aquí hay una función más simple con un objective similar. El uso de la memoria se puede ordenar alfabéticamente o por tamaño, se puede limitar a una cierta cantidad de objetos y se puede ordenar de forma ascendente o descendente. Además, a menudo trabajo con datos de 1GB +, por lo que la función cambia las unidades en consecuencia.

 showMemoryUse < - function(sort="size", decreasing=FALSE, limit) { objectList <- ls(parent.frame()) oneKB <- 1024 oneMB <- 1048576 oneGB <- 1073741824 memoryUse <- sapply(objectList, function(x) as.numeric(object.size(eval(parse(text=x))))) memListing <- sapply(memoryUse, function(size) { if (size >= oneGB) return(paste(round(size/oneGB,2), "GB")) else if (size >= oneMB) return(paste(round(size/oneMB,2), "MB")) else if (size >= oneKB) return(paste(round(size/oneKB,2), "kB")) else return(paste(size, "bytes")) }) memListing < - data.frame(objectName=names(memListing),memorySize=memListing,row.names=NULL) if (sort=="alphabetical") memListing <- memListing[order(memListing$objectName,decreasing=decreasing),] else memListing <- memListing[order(memoryUse,decreasing=decreasing),] #will run if sort not specified or "size" if(!missing(limit)) memListing <- memListing[1:limit,] print(memListing, row.names=FALSE) return(invisible(memListing)) } 

Y aquí hay algunos ejemplos de salida:

 > showMemoryUse(decreasing=TRUE, limit=5) objectName memorySize coherData 713.75 MB spec.pgram_mine 149.63 kB stoch.reg 145.88 kB describeBy 82.5 kB lmBandpass 68.41 kB 

Lamentablemente no tuve tiempo de probarlo extensivamente, pero aquí hay una sugerencia de memoria que no he visto antes. Para mí, la memoria requerida se redujo con más del 50%. Cuando lees cosas en R con, por ejemplo, read.csv, requieren cierta cantidad de memoria. Después de esto, puede guardarlos con save("Destinationfile",list=ls()) La próxima vez que abra R puede usar load("Destinationfile") Ahora el uso de la memoria puede haber disminuido. Sería bueno si alguien pudiera confirmar si esto produce resultados similares con un conjunto de datos diferente.

Nunca guardo un espacio de trabajo R. Utilizo scripts de importación y scripts de datos y genero objetos de datos especialmente grandes que no deseo recrear a menudo en los archivos. De esta manera, siempre comienzo con un espacio de trabajo nuevo y no necesito limpiar objetos grandes. Sin embargo, esa es una función muy buena.

Para ilustrar aún más la estrategia común de reinicios frecuentes, podemos usar littler, que nos permite ejecutar expresiones simples directamente desde la línea de comandos. Aquí hay un ejemplo que a veces uso para medir el tiempo de BLAS diferente para un crossprod simple.

  r -e'N< -3*10^3; M<-matrix(rnorm(N*N),ncol=N); print(system.time(crossprod(M)))' 

Igualmente,

  r -lMatrix -e'example(spMatrix)' 

carga el paquete Matrix (a través del paquete --packages | -l) y ejecuta los ejemplos de la función spMatrix. Como r siempre comienza 'nuevo', este método también es una buena prueba durante el desarrollo del paquete.

Por último, pero no por ello menos importante, también funcionan muy bien para el modo por lotes automático en scripts que utilizan el encabezado shebang '#! / Usr / bin / r'. Rscript es una alternativa donde el littler no está disponible (por ejemplo, en Windows).

Tanto para la velocidad como para la memoria, al construir un dataframe grande a través de una compleja serie de pasos, lo limpiaré periódicamente (el conjunto de datos en progreso que se está construyendo) en el disco, se agregará a todo lo que venía antes y luego lo reiniciaré . De esta forma, los pasos intermedios solo funcionan en marcos de datos pequeños (lo que es bueno, por ejemplo, la reducción de la velocidad de ralentización considerable con objetos más grandes). Se puede leer todo el conjunto de datos al final del proceso, cuando se han eliminado todos los objetos intermedios.

 dfinal < - NULL first <- TRUE tempfile <- "dfinal_temp.csv" for( i in bigloop ) { if( !i %% 10000 ) { print( i, "; flushing to disk..." ) write.table( dfinal, file=tempfile, append=!first, col.names=first ) first <- FALSE dfinal <- NULL # nuke it } # ... complex operations here that add data to 'dfinal' data frame } print( "Loop done; flushing to disk and re-reading entire data set..." ) write.table( dfinal, file=tempfile, append=TRUE, col.names=FALSE ) dfinal <- read.table( tempfile ) 

Solo para observar que las tables() del paquete data.table tables() parecen ser un reemplazo bastante bueno para la función personalizada de .ls.objects() (detallada en respuestas anteriores), aunque solo para data.frames / tables y no por ejemplo matrices, matrices, liza.

  1. Soy afortunado y mis grandes conjuntos de datos son guardados por el instrumento en “trozos” (subconjuntos) de aproximadamente 100 MB (32 bits binarios). Por lo tanto, puedo realizar pasos de preprocesamiento (eliminar partes no informativas, reducción de muestreo) secuencialmente antes de fusionar el conjunto de datos.

  2. Llamar a gc () “a mano” puede ayudar si el tamaño de los datos se acerca a la memoria disponible.

  3. A veces, un algoritmo diferente necesita mucha menos memoria.
    A veces hay una compensación entre la vectorización y el uso de la memoria.
    comparar: split y lapply frente a un ciclo for .

  4. En aras de un análisis de datos rápido y sencillo, a menudo trabajo primero con un pequeño subconjunto aleatorio ( sample () ) de los datos. Una vez que el script de análisis de datos / .Rnw haya terminado, el código de análisis de datos y los datos completos irán al servidor de cálculo para el cálculo de sobre noche / fin de semana / …

El uso de entornos en lugar de listas para manejar colecciones de objetos que ocupan una cantidad significativa de memoria de trabajo.

El motivo: cada vez que se modifica un elemento de una estructura de list , la lista completa se duplica temporalmente. Esto se convierte en un problema si el requisito de almacenamiento de la lista es aproximadamente la mitad de la memoria de trabajo disponible, porque los datos deben intercambiarse al disco duro lento. Los entornos, por otro lado, no están sujetos a este comportamiento y pueden tratarse de manera similar a las listas.

Aquí hay un ejemplo:

 get.data < - function(x) { # get some data based on x return(paste("data from",x)) } collect.data <- function(i,x,env) { # get some data data <- get.data(x[[i]]) # store data into environment element.name <- paste("V",i,sep="") env[[element.name]] <- data return(NULL) } better.list <- new.env() filenames <- c("file1","file2","file3") lapply(seq_along(filenames),collect.data,x=filenames,env=better.list) # read/write access print(better.list[["V1"]]) better.list[["V2"]] <- "testdata" # number of list elements length(ls(better.list)) 

Junto con estructuras tales como big.matrix o data.table que permiten alterar su contenido en el lugar, se puede lograr un uso de la memoria muy eficiente.

La función ll en el paquete gData puede mostrar el uso de memoria de cada objeto.

 gdata::ll(unit='MB') 

Con solo 4 GB de RAM (ejecutando Windows 10, por lo que creo que son aproximadamente 2 o más realistas de 1 GB), he tenido que ser muy cuidadoso con la asignación.

Uso data.table casi exclusivamente.

La función ‘fread’ le permite subconjunto de información por nombres de campo en la importación; solo importe los campos que realmente necesita para comenzar. Si está utilizando lectura de base R, anule las columnas espurias inmediatamente después de la importación.

Como sugiere 42 , siempre que sea posible, lo subconjunto dentro de las columnas inmediatamente después de importar la información.

Con frecuencia rm () los objetos del entorno tan pronto como ya no son necesarios, por ejemplo, en la siguiente línea después de usarlos para subconjunto de otra cosa, y llamo a gc ().

‘fread’ y ‘fwrite’ de data.table pueden ser muy rápidos en comparación con las lecturas y escrituras de la base R.

Como sugiere kpierce8 , casi siempre borro todo del medio ambiente y lo vuelvo a usar, incluso con miles / cientos de miles de archivos pequeños para pasar. Esto no solo mantiene el entorno “limpio” y mantiene baja la asignación de memoria, sino que, posiblemente debido a la gran falta de RAM disponible, R tiene una propensión a bloquearse frecuentemente en mi computadora; muy frecuentemente Tener la información respaldada en la propia unidad a medida que el código avanza a través de varias etapas significa que no tengo que comenzar desde el principio si se bloquea.

A partir de 2017, creo que los discos SSD más rápidos se ejecutan alrededor de unos GB por segundo a través del puerto M2. Tengo un SSD Kingston V300 (550 MB / s) realmente básico de 50 GB que uso como mi disco principal (tiene Windows y R en él). Guardo toda la información a granel en un plato barato de 500 GB WD. Muevo los conjuntos de datos al SSD cuando comienzo a trabajar en ellos. Esto, combinado con ‘fread’ y ‘fwrite’ing todo ha estado funcionando muy bien. He intentado usar ‘ff’, pero prefiero el primero. Sin embargo, las velocidades de lectura / escritura de 4K pueden crear problemas con esto; la copia de seguridad de un cuarto de millón de archivos de 1k (250MB) desde la SSD hasta el plato puede llevar horas. Por lo que sé, no hay ningún paquete R disponible que pueda optimizar automáticamente el proceso de “fragmentación”; Por ejemplo, observe cuánta memoria RAM tiene un usuario, pruebe las velocidades de lectura / escritura de la RAM / todas las unidades conectadas y luego sugiera un protocolo óptimo de “fragmentación”. Esto podría producir mejoras significativas en el flujo de trabajo / optimización de recursos; por ejemplo, divídalo en … MB para el ram -> divídalo en … MB para el SSD -> divídalo en … MB en el disco -> divídalo en … MB en la cinta. Podría muestrear los conjuntos de datos de antemano para darle una varilla de medida más realista para trabajar.

Muchos de los problemas en los que he trabajado en R implican la formación de combinaciones y pares de permutación, triples, etc., lo que hace que tener RAM limitada sea más una limitación, ya que a menudo al menos se expandirán exponencialmente en algún momento. Esto me ha hecho centrar la atención en la calidad en lugar de la cantidad de información que entra en ellos para empezar, en lugar de tratar de limpiarlo después, y en la secuencia de operaciones para preparar la información para empezar (comenzando con la operación más simple y aumentando la complejidad); por ejemplo, subconjunto, luego fusionar / unir, luego formar combinaciones / permutaciones, etc.

Parece que hay algunos beneficios al usar lectura y escritura de base R en algunos casos. Por ejemplo, la detección de errores dentro de ‘fread’ es tan buena que puede ser difícil tratar de obtener información muy desordenada en R para comenzar a limpiarla. La base R también parece ser mucho más fácil si estás usando Linux. La base R parece funcionar bien en Linux, Windows 10 usa ~ 20GB de espacio en disco, mientras que Ubuntu solo necesita unos GB, la RAM necesaria con Ubuntu es ligeramente menor. Pero he notado grandes cantidades de advertencias y errores al instalar paquetes de terceros en (L) Ubuntu. No recomendaría alejarme demasiado de (L) Ubuntu u otras distribuciones de stock con Linux, ya que se puede perder tanta compatibilidad general que hace que el proceso sea casi inútil (creo que la ‘unidad’ se cancelará en Ubuntu a partir de 2017). ) Me doy cuenta de que esto no funcionará bien con algunos usuarios de Linux, pero algunas de las distribuciones personalizadas están en el límite sin sentido más allá de la novedad (he pasado años usando solo Linux).

Con suerte, algo de eso podría ayudar a otros.

Si realmente quieres evitar las filtraciones, debes evitar crear objetos grandes en el entorno global.

Lo que suelo hacer es tener una función que haga el trabajo y devuelva NULL : todos los datos se leen y manipulan en esta función u otras a las que llama.

Esto no agrega nada a lo anterior, pero está escrito en el estilo simple y muy comentado que me gusta. Produce una tabla con los objetos ordenados en tamaño, pero sin algunos de los detalles que se dan en los ejemplos anteriores:

 #Find the objects MemoryObjects = ls() #Create an array MemoryAssessmentTable=array(NA,dim=c(length(MemoryObjects),2)) #Name the columns colnames(MemoryAssessmentTable)=c("object","bytes") #Define the first column as the objects MemoryAssessmentTable[,1]=MemoryObjects #Define a function to determine size MemoryAssessmentFunction=function(x){object.size(get(x))} #Apply the function to the objects MemoryAssessmentTable[,2]=t(t(sapply(MemoryAssessmentTable[,1],MemoryAssessmentFunction))) #Produce a table with the largest objects first noquote(MemoryAssessmentTable[rev(order(as.numeric(MemoryAssessmentTable[,2]))),]) 

Si está trabajando en Linux y desea utilizar varios procesos y solo tiene que realizar operaciones de lectura en uno o más objetos grandes, utilice makeForkCluster lugar de makePSOCKcluster . Esto también le ahorra el tiempo de enviar el objeto grande a los otros procesos.

Realmente aprecio algunas de las respuestas anteriores, siguiendo a @hadley y @Dirk que sugieren cerrar R y emitir la source y usar la línea de comando, se me ocurrió una solución que funcionó muy bien para mí. Tuve que lidiar con cientos de espectros de masas, cada uno ocupa alrededor de 20 Mb de memoria, así que utilicé dos scripts R, de la siguiente manera:

Primero un envoltorio:

 #!/usr/bin/Rscript --vanilla --default-packages=utils for(l in 1:length(fdir)) { for(k in 1:length(fds)) { system(paste("Rscript runConsensus.r", l, k)) } } 

con este script básicamente controlo lo que runConsensus.r mi script principalConsensus.r, y escribo la respuesta de datos para el resultado. Con esto, cada vez que el contenedor llama al script parece que se vuelve a abrir la R y se libera la memoria.

Espero eso ayude.

Además de las técnicas de administración de memoria más generales dadas en las respuestas anteriores, siempre trato de reducir el tamaño de mis objetos en la medida de lo posible. Por ejemplo, trabajo con matrices muy grandes pero muy dispersas, en otras palabras, matrices donde la mayoría de los valores son cero. Usando el paquete ‘Matrix’ (capitalización importante) pude reducir mis tamaños promedio de objetos de ~ 2GB a ~ 200MB de la siguiente manera:

 my.matrix < - Matrix(my.matrix) 

El paquete Matrix incluye formatos de datos que se pueden usar exactamente como una matriz regular (no es necesario cambiar el otro código) pero pueden almacenar datos dispersos de manera mucho más eficiente, ya sea que se carguen en la memoria o se guarden en el disco.

Además, los archivos sin procesar que recibo están en formato 'largo', donde cada punto de datos tiene las variables x, y, z, i . Mucho más eficiente para transformar los datos en una matriz de dimensiones x * y * z con solo la variable i .

Conozca sus datos y use un poco de sentido común.

También puede obtener algún beneficio utilizando knitr y colocando su script en Rmd chuncks.

Normalmente divido el código en diferentes fragmentos y selecciono uno que guardará un punto de control en la memoria caché o en un archivo RDS, y

Allí puede configurar un fragmento para que se guarde en “caché”, o puede decidir ejecutar o no un fragmento en particular. De esta forma, en una primera ejecución puede procesar solo “parte 1”, otra ejecución puede seleccionar solo “parte 2”, etc.

Ejemplo:

 part1 ```{r corpus, warning=FALSE, cache=TRUE, message=FALSE, eval=TRUE} corpusTw < - corpus(twitter) # build the corpus ``` part2 ```{r trigrams, warning=FALSE, cache=TRUE, message=FALSE, eval=FALSE} dfmTw <- dfm(corpusTw, verbose=TRUE, removeTwitter=TRUE, ngrams=3) ``` 

Como efecto secundario, esto también podría ahorrarle algunos dolores de cabeza en términos de reproducibilidad 🙂

Basado en la respuesta de @ Dirk y @ Tony, hice una pequeña actualización. El resultado fue la salida [1] antes de los valores de tamaño bonitos, por lo que saqué el capture.output que resolvió el problema:

 .ls.objects < - function (pos = 1, pattern, order.by, decreasing=FALSE, head=FALSE, n=5) { napply <- function(names, fn) sapply(names, function(x) fn(get(x, pos = pos))) names <- ls(pos = pos, pattern = pattern) obj.class <- napply(names, function(x) as.character(class(x))[1]) obj.mode <- napply(names, mode) obj.type <- ifelse(is.na(obj.class), obj.mode, obj.class) obj.prettysize <- napply(names, function(x) { format(utils::object.size(x), units = "auto") }) obj.size <- napply(names, utils::object.size) obj.dim <- t(napply(names, function(x) as.numeric(dim(x))[1:2])) vec <- is.na(obj.dim)[, 1] & (obj.type != "function") obj.dim[vec, 1] <- napply(names, length)[vec] out <- data.frame(obj.type, obj.size, obj.prettysize, obj.dim) names(out) <- c("Type", "Size", "PrettySize", "Rows", "Columns") if (!missing(order.by)) out <- out[order(out[[order.by]], decreasing=decreasing), ] if (head) out <- head(out, n) return(out) } # shorthand lsos <- function(..., n=10) { .ls.objects(..., order.by="Size", decreasing=TRUE, head=TRUE, n=n) } lsos() 

Esta es una respuesta más nueva a esta excelente pregunta anterior. De Hadley’s Advanced R:

 install.packages("pryr") library(pryr) object_size(1:10) ## 88 B object_size(mean) ## 832 B object_size(mtcars) ## 6.74 kB 

( http://adv-r.had.co.nz/memory.html )

Corriendo

 for (i in 1:10) gc(reset = T) 

de vez en cuando también ayuda a R a liberar memoria no utilizada pero aún no liberada.