在bash脚本中打开文件描述符并逐行读取文件时,脚本在处理70K行后终止并出现内存分配错误:
xmalloc:无法分配11541个字节(分配0个字节)
环境: MINGW32 Bash:3.1.20(4)-release(i686-pc-msys) 操作系统:Windows 7
输入文件的大小:每个1.2 GB
脚本如下:
#!/bin/bash
echo Left: $1
echo Right: $2
echo >"$1.diff"
echo >"$2.diff"
exec 4<"$1"
exec 5<"$2"
LINECOUNT=0
while [ $? == 0 ]
do
exec 0<&4
read LEFTLINE
exec 0<&5
read RIGHTLINE
if [ $? != 0 ]
then
exit -1
fi
LINECOUNT=$(($LINECOUNT + 1))
LINEMOD=$(($LINECOUNT % 1000))
if [[ $LINEMOD == 0 ]]
then
echo Line: $LINECOUNT
fi
if [ $LEFTLINE != $RIGHTLINE ]
then
echo $LEFTLINE >> "$1.diff"
echo $RIGHTLINE >> "$2.diff"
echo Mismatch found
fi
done
正如我上面所说,脚本工作了很长时间,处理大约70K行然后终止。我假设它终止,因为它耗尽了32位进程可以占用的所有内存。
脚本的目的是打开两个格式和长度相同的文件,并逐行比较。它会将两个输出文件创建到写出不匹配行的位置。我不得不编写脚本,因为我使用的所有比较工具都因“内存不足”错误而崩溃或被绞死。当我的剧本也崩溃时,我感到很惊讶。我不得不在C ++中重写它以使其工作。现在我试图理解为什么bash脚本失败了。从理论上讲,它不应该在内存中累积文件内容。相反,它应该一次读取一行并推进文件指针。我试图理解为什么它崩溃了。也许还有另一种解决我的问题的方法,你可以推荐我可以实现为bash脚本。
更新:测试了以下修改。它也崩溃了。
while IFS= read -u4 -r LEFTLINE && IFS= read -u5 -r RIGHTLINE
do
LINECOUNT=$(($LINECOUNT + 1))
LINEMOD=$(($LINECOUNT % 1000))
答案 0 :(得分:0)
通过评论中的人们对问题的宝贵意见,找到了解决方案。 Petesh正确地评论说以前版本的bash中存在导致内存泄漏的错误(或许多错误)。 Here是Petesh提供的票证的链接。幸运的是,泄漏是在更新版本的bash中修复的。 所以解决方案是更新bash。我安装了cygwin和bash版本4.1.17(9)-release(i686-pc-cygwin)并且我的脚本成功完成,只消耗了1.5 Mb的内存记忆增加。 John Zwinch还测试了Bash 4.1.5,x86_64,并确认该版本中的错误也得到了修复。
在解决问题的同时,Mark Setchell和John Zwinck建议对脚本进行一些改进。这些修改并没有解决问题,但使用不同的文件格式使脚本更简单,更可靠。该脚本的最终版本如下:
#!/bin/bash
echo Left: $1
echo Right: $2
>"$1.diff"
>"$2.diff"
LINECOUNT=0
while IFS= read -u4 -r LEFTLINE && IFS= read -u5 -r RIGHTLINE
do
LINECOUNT=$(($LINECOUNT + 1))
LINEMOD=$(($LINECOUNT % 1000))
if [[ $LINEMOD == 0 ]]
then
echo Line: $LINECOUNT
fi
if [ "$LEFTLINE" != "$RIGHTLINE" ]
then
echo $LEFTLINE >> "$1.diff"
echo $RIGHTLINE >> "$2.diff"
echo Mismatch found
fi
done 4<"$1" 5<"$2"