100 轮循环 bash 脚本中的分段错误(核心已转储)
Segmentation fault (core dumped) over a 100 round loop bash script
我知道关于那个著名的 "Segmentation fault core dump" 有很多问题,但就我所见, C/C++ 涉及其中的大部分。但我的问题是特定于 bash 脚本的,所以我在这里试试运气。
我正在 运行 编写一个模拟器脚本(400 多行所以我不能给你看代码,可以吗?)它使用骰子和配置文件设置和计算两个角色之间的战斗(就像你会的那样在龙与地下城桌面角色扮演游戏中做)。我有一个重新初始化功能,可以从头开始重新设置战斗,以便在有赢家时可以开始新的战斗。在 X 轮结束时,会显示其中的一些值(命中百分比、每轮 %block %hp 等)。
如果我设置 1、50 或 100 回合(100 场战斗),没关系,它 运行 很完美。但是超过 130~ 次战斗,突然间,它显示 "Segmentation fault (core dumped)" 消息而没有任何延迟或其他并发症。
我对它有一个大致的了解,但我无法解释它为什么会发生,我无法解决它,我不知道该怎么做,或者要寻找什么。
在浏览了很多主题之后我可以说的一些笔记:
没有导入,没有基于命令系统,没有sed,awk,没有数组,没有"complicated"命令。我只是在玩变量(整数)。没有字符串。最"complexe"的命令(获取随机数)大概是
(echo $((1 + RANDOM % 20)))
我的条件都是这样
if [[ "$Skill_Block2" == "Yes" ]];
then
在双引号之间使用双括号和变量(我听说在条件中忘记双引号变量可能会导致问题)。
没有&&或||或 -a 或 -o (我还读到使用直接 "if" 语句会更好)
整个脚本都是围绕函数构建的(更容易修改/实现)。计算伤害的函数由一个函数调用,该函数检查一个角色是否可以躲避成功的攻击,该攻击已被另一个允许该攻击成功或失败的函数降落。等等,我不知道这是不是一个好的开发方式,但到目前为止"worked"。
我有口音和法语字符,但我的 OS 版本(Ubuntu)似乎很好地管理了它们。
我几乎重复了每一个决议,所以我可以跟踪错误。也许显示这么多文本正在占用我的虚拟内存?但老实说,我绝不会期望在 Linux 上出现这种情况。
我不认为我有无限循环,因为我可以 运行 它 50++ 次而没有任何问题,完全相同的顺序。
为了显示统计数据,我使用了一种肮脏的方式(我认为):
touch statistique.txt
echo "#|Player 1|Player 2" > statistique.txt
echo "ATT OK|$Number_Touch_OK1|$Number_Touch_OK1" >> statistique.txt
echo "ATT Failed|$Number_Hit_Failed1|$Number_Hit_Failed2" >> statistique.txt
echo "DEF Tried |$Number_Dodge_Tried1|$Number_Dodge_Tried2" >> statistique.txt
[...]
echo "Victory Number|$Victory1|$Victory2" >> statistique.txt
echo " "
column statistique.txt -t -s "|"
我想知道 EOF,但我不确定变量是否会被解释。但至少我有一个格式很好的文本。
我的 Ubuntu 在我的 Windows 上是 运行。可能是问题所在?
所以我来了。我感到很困惑,我不太热衷于将此消息作为没有任何代码的文字墙发布,因为它太长了(但如果有人足够勇敢,我可以分享代码,没问题)。
我在 bash 上看到的关于内存泄漏的消息太少了,所以...我无法想象 Linux OS 运行 内存不足 如果您有任何想法,建议, 软件(我试过 Valgrind,但同样,我不确定它是否适用于 bash 脚本),请告诉我。
编辑:这是文件 (solveur.sh):
https://github.com/IlliciteS/script
正如评论中所指出的,您的程序无休止地递归。随着递归的每一级消耗更多的内存,bash 遇到分段错误。这是重现问题的最小脚本(包含在 bash -c
内,这样您的交互式 shell 就不会崩溃):
$ bash -c 'f() { f; }; f'
Segmentation fault (core dumped)
您可以通过使用 bash 的 FUNCNEST
变量限制最大递归级别来防止段错误。然而,这只会更优雅地中止一点。要解决实际问题,您必须重写脚本。
要确定问题,您可以查看脚本的调用图:
此图中的每个循环都可能使调用堆栈达到最大值。一点递归就可以了。但是对于您的任务,循环似乎更自然。我将从使用循环开始新的战斗开始。删除 Relance_Match()
并将您的主要 "method" 更改为
for ((i=0; i<Nombre_Match_Total; i++)); do
Who_start_fight
echo "..."
Reinitialisation_Carac_New_Match
done
echo "..."
Statistique
与递归无关的进一步改进
您可以使用数组极大地简化脚本。现在,每个玩家都有自己的一组变量和代码片段,例如
# for player one
Victoire1=0
Touch1() {
# lots of code using <insertThingHere>1, e.g.
((Victoire1++))
}
# for player two
Victoire2=0
Touch2() {
# the same code as in Touch1, but with <insertThingHere>2 instead, e.g.
((Victoire2++))
}
使用数组可以简化为
Victoire=(0 0)
Touch() {
player=
# lots of code using <insertThingHere>[player], e.g.
((Victoire[player]++));
}
我知道关于那个著名的 "Segmentation fault core dump" 有很多问题,但就我所见, C/C++ 涉及其中的大部分。但我的问题是特定于 bash 脚本的,所以我在这里试试运气。
我正在 运行 编写一个模拟器脚本(400 多行所以我不能给你看代码,可以吗?)它使用骰子和配置文件设置和计算两个角色之间的战斗(就像你会的那样在龙与地下城桌面角色扮演游戏中做)。我有一个重新初始化功能,可以从头开始重新设置战斗,以便在有赢家时可以开始新的战斗。在 X 轮结束时,会显示其中的一些值(命中百分比、每轮 %block %hp 等)。
如果我设置 1、50 或 100 回合(100 场战斗),没关系,它 运行 很完美。但是超过 130~ 次战斗,突然间,它显示 "Segmentation fault (core dumped)" 消息而没有任何延迟或其他并发症。
我对它有一个大致的了解,但我无法解释它为什么会发生,我无法解决它,我不知道该怎么做,或者要寻找什么。
在浏览了很多主题之后我可以说的一些笔记:
没有导入,没有基于命令系统,没有sed,awk,没有数组,没有"complicated"命令。我只是在玩变量(整数)。没有字符串。最"complexe"的命令(获取随机数)大概是
(echo $((1 + RANDOM % 20)))
我的条件都是这样
if [[ "$Skill_Block2" == "Yes" ]];
then
在双引号之间使用双括号和变量(我听说在条件中忘记双引号变量可能会导致问题)。
没有&&或||或 -a 或 -o (我还读到使用直接 "if" 语句会更好)
整个脚本都是围绕函数构建的(更容易修改/实现)。计算伤害的函数由一个函数调用,该函数检查一个角色是否可以躲避成功的攻击,该攻击已被另一个允许该攻击成功或失败的函数降落。等等,我不知道这是不是一个好的开发方式,但到目前为止"worked"。
我有口音和法语字符,但我的 OS 版本(Ubuntu)似乎很好地管理了它们。
我几乎重复了每一个决议,所以我可以跟踪错误。也许显示这么多文本正在占用我的虚拟内存?但老实说,我绝不会期望在 Linux 上出现这种情况。
我不认为我有无限循环,因为我可以 运行 它 50++ 次而没有任何问题,完全相同的顺序。
为了显示统计数据,我使用了一种肮脏的方式(我认为):
touch statistique.txt
echo "#|Player 1|Player 2" > statistique.txt
echo "ATT OK|$Number_Touch_OK1|$Number_Touch_OK1" >> statistique.txt
echo "ATT Failed|$Number_Hit_Failed1|$Number_Hit_Failed2" >> statistique.txt
echo "DEF Tried |$Number_Dodge_Tried1|$Number_Dodge_Tried2" >> statistique.txt
[...]
echo "Victory Number|$Victory1|$Victory2" >> statistique.txt
echo " "
column statistique.txt -t -s "|"
我想知道 EOF,但我不确定变量是否会被解释。但至少我有一个格式很好的文本。
我的 Ubuntu 在我的 Windows 上是 运行。可能是问题所在?
所以我来了。我感到很困惑,我不太热衷于将此消息作为没有任何代码的文字墙发布,因为它太长了(但如果有人足够勇敢,我可以分享代码,没问题)。 我在 bash 上看到的关于内存泄漏的消息太少了,所以...我无法想象 Linux OS 运行 内存不足 如果您有任何想法,建议, 软件(我试过 Valgrind,但同样,我不确定它是否适用于 bash 脚本),请告诉我。
编辑:这是文件 (solveur.sh): https://github.com/IlliciteS/script
正如评论中所指出的,您的程序无休止地递归。随着递归的每一级消耗更多的内存,bash 遇到分段错误。这是重现问题的最小脚本(包含在 bash -c
内,这样您的交互式 shell 就不会崩溃):
$ bash -c 'f() { f; }; f'
Segmentation fault (core dumped)
您可以通过使用 bash 的 FUNCNEST
变量限制最大递归级别来防止段错误。然而,这只会更优雅地中止一点。要解决实际问题,您必须重写脚本。
要确定问题,您可以查看脚本的调用图:
此图中的每个循环都可能使调用堆栈达到最大值。一点递归就可以了。但是对于您的任务,循环似乎更自然。我将从使用循环开始新的战斗开始。删除 Relance_Match()
并将您的主要 "method" 更改为
for ((i=0; i<Nombre_Match_Total; i++)); do
Who_start_fight
echo "..."
Reinitialisation_Carac_New_Match
done
echo "..."
Statistique
与递归无关的进一步改进
您可以使用数组极大地简化脚本。现在,每个玩家都有自己的一组变量和代码片段,例如
# for player one
Victoire1=0
Touch1() {
# lots of code using <insertThingHere>1, e.g.
((Victoire1++))
}
# for player two
Victoire2=0
Touch2() {
# the same code as in Touch1, but with <insertThingHere>2 instead, e.g.
((Victoire2++))
}
使用数组可以简化为
Victoire=(0 0)
Touch() {
player=
# lots of code using <insertThingHere>[player], e.g.
((Victoire[player]++));
}