gpt4 book ai didi

xml - 在 Windows 上使用包 XML 时发生内存泄漏

转载 作者:可可西里 更新时间:2023-11-01 12:40:02 29 4
gpt4 key购买 nike

在阅读了 Memory leaks parsing XML in r(包括链接的帖子)和 this 在 R Help 上的帖子后,考虑到又过了一段时间,我仍然认为这是一个值得关注的未解决问题,因为 XML 包在整个 R 世界中被广泛使用。

因此,请将此视为后续帖子和/或引用,希望对问题进行详尽而简洁的说明

问题

以一种随后可以用 XPath 搜索的方式解析 XML/HTML 文档需要在内部使用 C 指针 (AFAIU)。似乎至少在 MS Windows 上(我在 Windows 8.1、64 位上运行)这些引用没有被垃圾收集器正确识别。因此消耗的内存没有正确释放,导致 R 进程在某个时候卡住。

目前的主要发现

在我看来,XML:free 和/或 gc 确实/不识别解析 XML/HTML 文档时涉及的所有内存通过 xmlParsehtmlParse 并随后使用 xpathApply 或类似的方法处理它们:

报告的OS 任务 (Rterm.exe) 的内存使用量加起来非常快,而报告的 R 进程内存“从 R 内部看” (function memory.size) 适度增加(相比之下,即)。请参阅下面的大量解析循环前后的列表元素 mem_rmem_osratio

总而言之,加上推荐的所有东西(freermgc),内存使用仍然总是 在调用 xmlParse 等时增加。只是多少的问题。所以恕我直言,一定还有什么地方不能正常工作。


插图

我从 Duncan 的 Omegahat git repository 借用了分析代码。

一些准备工作:

Sys.setenv("LANGUAGE"="en")   
require("compiler")
require("XML")

> sessionInfo()
R version 3.1.0 (2014-04-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=German_Germany.1252 LC_CTYPE=German_Germany.1252
[3] LC_MONETARY=German_Germany.1252 LC_NUMERIC=C
[5] LC_TIME=German_Germany.1252

attached base packages:
[1] compiler stats graphics grDevices utils datasets methods
[8] base

other attached packages:
[1] XML_3.98-1.1

我们需要的功能:

getTaskMemoryByPid <- cmpfun(function(
pid=Sys.getpid()
) {
cmd <- sprintf("tasklist /FI \"pid eq %s\" /FO csv", pid)
mem <- read.csv(text=shell(cmd, intern = TRUE), stringsAsFactors=FALSE)[,5]
mem <- as.numeric(gsub("\\.|\\s|K", "", mem))/1000
mem
}, options=list(suppressAll=TRUE))

memoryLeak <- cmpfun(function(
x=system.file("exampleData", "mtcars.xml", package="XML"),
n=10000,
use_text=FALSE,
xpath=FALSE,
free_doc=FALSE,
clean_up=FALSE,
detailed=FALSE
) {
if(use_text) {
x <- readLines(x)
}
## Before //
mem_os <- getTaskMemoryByPid()
mem_r <- memory.size()
prof_1 <- memory.profile()
mem_before <- list(mem_r=mem_r,
mem_os=mem_os, ratio=mem_os/mem_r)

## Per run //
mem_perrun <- lapply(1:n, function(ii) {
doc <- xmlParse(x, asText=use_text)
if (xpath) {
res <- xpathApply(doc=doc, path="/blah", fun=xmlValue)
rm(res)
}
if (free_doc) {
free(doc)
}
rm(doc)
out <- NULL
if (detailed) {
out <- list(
profile=memory.profile(),
size=memory.size()
)
}
out
})
has_perrun <- any(sapply(mem_perrun, length) > 0)
if (!has_perrun) {
mem_perrun <- NULL
}

## Garbage collect //
mem_gc <- NULL
if(clean_up) {
gc()
tmp <- gc()
mem_gc <- list(gc_mb=tmp["Ncells", "(Mb)"])
}

## After //
mem_os <- getTaskMemoryByPid()
mem_r <- memory.size()
prof_2 <- memory.profile()
mem_after <- list(mem_r=mem_r,
mem_os=mem_os, ratio=mem_os/mem_r)
list(
before=mem_before,
perrun=mem_perrun,
gc=mem_gc,
after=mem_after,
comparison_r=data.frame(
before=prof_1,
after=prof_2,
increase=round((prof_2/prof_1)-1, 4)
),
increase_r=(mem_after$mem_r/mem_before$mem_r)-1,
increase_os=(mem_after$mem_os/mem_before$mem_os)-1
)
}, options=list(suppressAll=TRUE))

结果

场景一

小知识:启用垃圾收集,XML 文档被解析 n 次但通过 xpathApply 搜索

注意操作系统内存与 R 内存的比率:

之前:1.364832

之后:1.322702

res <- memoryLeak(clean_up=TRUE, n=50000)
save(res, file=file.path(tempdir(), "memory-profile-1.rdata"))

> res
$before
$before$mem_r
[1] 37.42

$before$mem_os
[1] 51.072

$before$ratio
[1] 1.364832


$perrun
NULL

$gc
$gc$gc_mb
[1] 45


$after
$after$mem_r
[1] 63.21

$after$mem_os
[1] 83.608

$after$ratio
[1] 1.322702


$comparison_r
before after increase
NULL 1 1 0.0000
symbol 7387 7392 0.0007
pairlist 190383 390633 1.0518
closure 5077 55085 9.8499
environment 1032 51032 48.4496
promise 5226 105226 19.1351
language 54675 54791 0.0021
special 44 44 0.0000
builtin 648 648 0.0000
char 8746 8763 0.0019
logical 9081 9084 0.0003
integer 22804 22807 0.0001
double 2773 2783 0.0036
complex 1 1 0.0000
character 44522 94569 1.1241
... 0 0 NaN
any 0 0 NaN
list 19946 19951 0.0003
expression 1 1 0.0000
bytecode 16049 16050 0.0001
externalptr 1487 1487 0.0000
weakref 391 391 0.0000
raw 392 392 0.0000
S4 1392 1392 0.0000

$increase_r
[1] 0.6892036

$increase_os
[1] 0.6370614

场景2

小知识:启用垃圾收集,显式调用 free,XML 文档被解析 n 次但通过 xpathApply 搜索

注意操作系统内存与 R 内存的比率:

之前:1.315249

之后:1.222143

res <- memoryLeak(clean_up=TRUE, free_doc=TRUE, n=50000)
save(res, file=file.path(tempdir(), "memory-profile-2.rdata"))
> res

$before
$before$mem_r
[1] 63.48

$before$mem_os
[1] 83.492

$before$ratio
[1] 1.315249


$perrun
NULL

$gc
$gc$gc_mb
[1] 69.3


$after
$after$mem_r
[1] 95.92

$after$mem_os
[1] 117.228

$after$ratio
[1] 1.222143


$comparison_r
before after increase
NULL 1 1 0.0000
symbol 7454 7454 0.0000
pairlist 392455 592466 0.5096
closure 55104 105104 0.9074
environment 51032 101032 0.9798
promise 105226 205226 0.9503
language 55592 55592 0.0000
special 44 44 0.0000
builtin 648 648 0.0000
char 8847 8848 0.0001
logical 9141 9141 0.0000
integer 23109 23111 0.0001
double 2802 2807 0.0018
complex 1 1 0.0000
character 94775 144781 0.5276
... 0 0 NaN
any 0 0 NaN
list 20174 20177 0.0001
expression 1 1 0.0000
bytecode 16265 16265 0.0000
externalptr 1488 1487 -0.0007
weakref 392 391 -0.0026
raw 393 392 -0.0025
S4 1392 1392 0.0000

$increase_r
[1] 0.5110271

$increase_os
[1] 0.4040627

场景 3

要点:启用垃圾收集,显式调用 free,XML 文档被解析 n 次并通过 xpathApply搜索/每次。

注意操作系统内存与 R 内存的比率:

之前:1.220429

之后:13.15629 (!)

res <- memoryLeak(clean_up=TRUE, free_doc=TRUE, xpath=TRUE, n=50000)
save(res, file=file.path(tempdir(), "memory-profile-3.rdata"))
res
$before
$before$mem_r
[1] 95.94

$before$mem_os
[1] 117.088

$before$ratio
[1] 1.220429


$perrun
NULL

$gc
$gc$gc_mb
[1] 93.4


$after
$after$mem_r
[1] 124.64

$after$mem_os
[1] 1639.8

$after$ratio
[1] 13.15629


$comparison_r
before after increase
NULL 1 1 0.0000
symbol 7454 7460 0.0008
pairlist 592458 793042 0.3386
closure 105104 155110 0.4758
environment 101032 151032 0.4949
promise 205226 305226 0.4873
language 55592 55882 0.0052
special 44 44 0.0000
builtin 648 648 0.0000
char 8847 8867 0.0023
logical 9142 9162 0.0022
integer 23109 23112 0.0001
double 2802 2832 0.0107
complex 1 1 0.0000
character 144775 194819 0.3457
... 0 0 NaN
any 0 0 NaN
list 20174 20177 0.0001
expression 1 1 0.0000
bytecode 16265 16265 0.0000
externalptr 1488 1487 -0.0007
weakref 392 391 -0.0026
raw 393 392 -0.0025
S4 1392 1392 0.0000

$increase_r
[1] 0.2991453

$increase_os
[1] 13.00485

我也尝试了不同的版本。好吧,我尝试尝试了;-)

来源,来自 omegahat.org

仅供引用:最新的 Rtools 3.1 已安装并包含在 Windows PATH 中(例如,从源代码安装 stringr 工作正常)。

> install.packages("XML", repos="http://www.omegahat.org/R", type="source")
trying URL 'http://www.omegahat.org/R/src/contrib/XML_3.98-1.tar.gz'
Content type 'application/x-gzip' length 1543387 bytes (1.5 Mb)
opened URL
downloaded 1.5 Mb

* installing *source* package 'XML' ...
Please define LIB_XML (and LIB_ZLIB, LIB_ICONV)
Warning: running command 'sh ./configure.win' had status 1
ERROR: configuration failed for package 'XML'
* removing 'R:/home/apps/lsqmapps/apps/r/R-3.1.0/library/XML'
* restoring previous 'R:/home/apps/lsqmapps/apps/r/R-3.1.0/library/XML'

The downloaded source packages are in
'C:\Users\rappster_admin\AppData\Local\Temp\RtmpQFZ2Ck\downloaded_packages'
Warning messages:
1: running command '"R:/home/apps/lsqmapps/apps/r/R-3.1.0/bin/x64/R" CMD INSTALL -l "R:\home\apps\lsqmapps\apps\r\R-3.1.0\library" C:\Users\RAPPST~1\AppData\Local\Temp\RtmpQFZ2Ck/downloaded_packages/XML_3.98-1.tar.gz' had status 1
2: In install.packages("XML", repos = "http://www.omegahat.org/R", :
installation of package 'XML' had non-zero exit status

Github

我没有遵循 github repo 上 README 中的建议,因为它指向仅包含 3.94-0 版本的 tar.gzthis directory(而我们在 CRAN 上位于 3.98-1.1)。

即使声明 gihub 存储库不在标准 R 包结构中,我还是尝试了 install_github - 但失败了 ;-)

require("devtools")
> install_github(repo="XML", username="omegahat")
Installing github repo XML/master from omegahat
Downloading master.zip from https://github.com/omegahat/XML/archive/master.zip
Installing package from C:\Users\RAPPST~1\AppData\Local\Temp\RtmpQFZ2Ck/master.zip
Installing XML
"R:/home/apps/lsqmapps/apps/r/R-3.1.0/bin/x64/R" --vanilla CMD INSTALL \
"C:\Users\rappster_admin\AppData\Local\Temp\RtmpQFZ2Ck\devtools15c82d7c2b4c\XML-master" \
--library="R:/home/apps/lsqmapps/apps/r/R-3.1.0/library" --with-keep.source \
--install-tests

* installing *source* package 'XML' ...
Please define LIB_XML (and LIB_ZLIB, LIB_ICONV)
Warning: running command 'sh ./configure.win' had status 1
ERROR: configuration failed for package 'XML'
* removing 'R:/home/apps/lsqmapps/apps/r/R-3.1.0/library/XML'
* restoring previous 'R:/home/apps/lsqmapps/apps/r/R-3.1.0/library/XML'
Error: Command failed (1)

最佳答案

虽然它仍处于起步阶段(只有几个月大!),并且有一些怪癖,但 Hadley Wickham 已经编写了一个用于 XML 解析的库 xml2,可以在Github 在 https://github.com/hadley/xml2 .它仅限于读取而不是写入 XML,但对于解析 XML,我一直在试验,看起来它可以完成工作,而不会出现 xml 包的内存泄漏!它提供的功能包括:

  • read_xml() 读取 XML 文件
  • xml_children()获取一个节点的子节点
  • xml_text() 获取标签内的文本
  • xml_attrs() 获取节点属性和值的字符向量,可以使用 as.list()

请注意,您仍然需要确保在处理完 XML 节点对象后 rm(),并使用 gc() 强制进行垃圾回收,但内存实际上确实被释放到操作系统(免责声明:仅在 Windows 7 上测试过,但这似乎是最“内存泄漏”的平台)。

希望这对某人有帮助!

关于xml - 在 Windows 上使用包 XML 时发生内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23696391/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com