作者LaPass (LaPass)
看板java
标题Re: [问题] 递回次数有没有上限?
时间Thu Mar 1 22:09:47 2012
直接用个范例来说明:
这个Method纯粹只是为了当范例用的
当传进去的x不等於y的时候,他会把x+1,然後继续递回下去
直到x==y为止
int methodt (double x , double y)
{
if (x==y) return x;
else return Methodt(x+1,y);
}
假设,现在x = 1, y = 3
执行 methodt(1,3);
那程式会这样跑:
1.
methodt(1,3); <= 呼叫method,建立一个methodt的「域」
2.
int methodt (double x , double y) <= 宣告了 x 跟 y 两个变数
{ 也就是说,记忆体中多这两个值
if (x==y) return x; 一般的IDE都会附检视变数的功能
else return Methodt(x+1,y); 请把他找出来,看看记忆体中有
} 哪些变数
3.
int methodt (double x , double y)
{
if (x==y) return x; <= 比较 x==y ,这应该不用解释
else return Methodt(x+1,y);
}
3.
int methodt (double x , double y)
{
if (x==y) return x;
else return
Methodt(x+1,y); <= 把 x+1,再次呼叫Methodt
} 再次宣告一个域
4.
int methodt (double x , double y) <= 再次宣告
x 跟
y 两个变数
{ 并令
x =
x+1 ,
y =
y
if (x==y) return x; 现在记忆体中有
methodt methodt两个域
else return Methodt(x+1,y);
x=1
y=3
x=2
y=3 四个变数
}
5.
int methodt (double x , double y)
{
if (x==y) return x;
else return
Methodt(x+1,y); <= 再次宣告一个域
}
6.
int methodt (double x , double y)
{
if (x==y) return x; <= 到这一步时,记忆体中有3个域
else return Methodt(x+1,y); 6个变数
}
7.
int methodt (double x , double y)
{
if (x==y)
return x; <= 因为条件成立,所以返回
x
else return Methodt(x+1,y);
}
8.
int methodt (double x , double y)
{
if (x==y) return x;
else return Methodt(x+1,y);
} <= 返回值後,释放
x y 两个变数
并删除域,留给JVM做GC
9.
int methodt (double x , double y)
{
if (x==y) return x;
else
return Methodt(x+1,y); <= 返回
3 ,以下同上
}
//=================================================================
以上是递回的基本步骤
可以看的到,呼叫一次Methodt就会建立一个域,并在记忆体中占了两个变数
有些程式的写法可能会出问题
例如说...
Methodt(4,3);
这样的话,程式会无止尽的递回下去,直到记忆体用光
跳出StackOverflowError
遇到StackOverflowError,绝大多数都是这一种状况
另一种
是无意义的「巨大」变数
例如:
void Methodt (byte[] a)
{
//DoSomeThing
byte b = new byte[a.length];
System.arraycopy(a, 0, b, 0, a.length); <= 拷贝阵列
Methodt(b);
}
万一那个 a 是一张5MB的图片的话
递回一层就会吃掉5MB
通常跑不了几层就会 StackOverflowError
※感谢sbrhsieh大大指正
这种状况出现的会是 OutOfMemoryError ,而不是StackOverflowError
因为byte[]是配置在heap中,而不是stack中
※ 引述《tossakite (昱)》之铭言:
: 不好意思我是java的新手(刚学第五天...)
: 如果发问不得当真的很抱歉...
: 我目前正在写小画家
: 但刚刚写油漆桶功能的时候却遇到奇怪的问题
: 基本上我是用Depth First Search的概念写成递回函数
: 从滑鼠点下去的那点作为树根 一直向外扩散寻找需要变色的像素
: 扩散顺序是先往右边找 再往上、往左 最後往下找
: 结果测试结果发现
: 如果用铅笔圈出一块小面积(有测过奇形怪状) 油漆桶都可以成功把内部着色
: 但如果面积稍微大一点(大概超过50x50个像素的话)
: 它就无法着色了
: 所以怀疑是如果递回呼叫太多次它就会发生问题
: 测试了一下也发现
: 如果面积太大的话 递回总是跑到一半就自动被强行结束(每次结束的点都不一样)
: 可是递回次数应该不可能会有限制吧!?
: 上网都没有查到这方面有什麽限制存在
: 也不太可能是演算法出错 因为面积够小还是可以成功着色
: 由於程式码有点多(大概25行) 不太确定要不要PO出来
: 递回函数传入的参数有三个
: 一个是BufferedImage
: 一个是跟像素数量一样多的布林二维阵列 还有一个Point
: 难道是传入的参数太庞大的问题?
: 如果有需要检查程式码的话我可以再贴出来@@
: 烦请高手解惑!!
: ----------------------------
: 对不起我不知道有错误讯息这种东西QQQQ
: 是下面这个吗?
: Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
: 它後面接了很多 at .....
: 前几个是这样
: at java.awt.image.DirectColorModel.getRGB(DirectColorModel.java:438)
: at java.awt.image.DirectColorModel.getRGB(DirectColorModel.java:704)
: at java.awt.image.BufferedImage.getRGB(BufferedImage.java:871)
: at painter.test2.recursive(test2.java:887)
: at painter.test2.recursive(test2.java:891)
: at painter.test2.recursive(test2.java:891)
: 之後全部都是recursive函数
: 对不起我以後会注意版规的QQ
--
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 125.233.156.129
1F:推 tossakite:原来如此!!! 很感谢你的详细说明~:D 03/01 23:57
2F:→ tossakite:看来只好放弃美丽的递回了QQ 用回圈写DFS感觉好难.... 03/01 23:59
3F:→ LaPass:其实我觉得你想办法把几个比较「笨重」的参数移到外面,应 03/02 00:50
4F:→ LaPass:该就可以解决问题了.... 03/02 00:51
5F:推 tossakite:我努力把参数缩到剩一个Point物件 还是画不了大面积... 03/02 01:41
6F:推 tossakite:我把它写成完全不用传参数 函数里也没有宣告任何新东西 03/02 02:06
7F:→ tossakite:竟然还是StackOverFlow...!! 请问所谓的域很耗资源吗? 03/02 02:09
8F:推 eieio:你 50x50 的区域,写 recursive 的话就有可能有 250 层 03/02 02:28
9F:→ LaPass:之前除这种错时,跑到一万层都没问题.... 03/02 09:07
试着加这一段下去看看
static int num = 0;
int Methodt()
{
num++;
//输出 num ,如果太多层的话,可以用 if(num%100==0)去减少输出
int re = Methodt();
num--;
return re;
}
这样就可以知道跑到第几层了
我现在才发现范例的传回值是错的....
※ 编辑: LaPass 来自: 61.59.16.65 (03/02 11:07)
10F:→ gameking:会不会是电脑设备的问题 记忆体太小? 03/02 15:17
11F:推 tossakite:蛤真的吗? 可是4G应该还算OK吧@@ 03/02 23:36
12F:推 tossakite:它最高可以画到6000左右个像素 但很奇妙的是 超过6000 03/02 23:50
13F:→ tossakite:个像素的话 它几乎递回跑4000多次就停了(但偶尔会8000多 03/02 23:53
14F:→ tossakite:阿应该要计算层才对= = 等一下我重写... 03/02 23:58
15F:→ tossakite:结果是 极限是在2068~2074层之间很规律的周期变化... 03/03 00:04