且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么这个方法打印 4?

更新时间:2022-11-24 08:48:00

我认为其他人已经很好地解释了为什么 cnt > 0,但是没有足够的细节来解释为什么 cnt = 4,以及为什么 cnt 变化如此之大在不同的设置之间.我将尝试在这里填补这个空白.

I think the others have done a good job at explaining why cnt > 0, but there's not enough details regarding why cnt = 4, and why cnt varies so widely among different settings. I will attempt to fill that void here.

  • X 是总堆栈大小
  • M是我们第一次进入main时使用的栈空间
  • R是每次进入main时增加的栈空间
  • P 是运行 System.out.println
  • 所需的堆栈空间
  • X be the total stack size
  • M be the stack space used when we enter main the first time
  • R be the stack space increase each time we enter into main
  • P be the stack space necessary to run System.out.println

当我们第一次进入 main 时,剩下的空间是 X-M.每个递归调用占用 R 更多内存.所以对于 1 次递归调用(比原来多 1 次),内存使用量为 M + R.假设 C 递归调用成功后抛出 ***Error,即 M + C * R X.在第一个 ***Error 的时候,还剩下 X - M - C * R 内存.

When we first get into main, the space left over is X-M. Each recursive call takes up R more memory. So for 1 recursive call (1 more than original), the memory use is M + R. Suppose that ***Error is thrown after C successful recursive calls, that is, M + C * R <= X and M + C * (R + 1) > X. At the time of the first ***Error, there's X - M - C * R memory left.

为了能够运行 System.out.prinln,我们需要在堆栈上留下 P 量的空间.如果碰巧 X - M - C * R >= P,那么将打印 0.如果 P 需要更多空间,那么我们从堆栈中删除帧,以 cnt++ 为代价获得 R 内存.

To be able to run System.out.prinln, we need P amount of space left on the stack. If it so happens that X - M - C * R >= P, then 0 will be printed. If P requires more space, then we remove frames from the stack, gaining R memory at the cost of cnt++.

println 最终能够运行时,X - M - (C - cnt) * R >= P.因此,如果 P 对于特定系统来说很大,那么 cnt 也会很大.

When println is finally able to run, X - M - (C - cnt) * R >= P. So if P is large for a particular system, then cnt will be large.

让我们用一些例子来看看这个.

Let's look at this with some examples.

示例1:假设

  • X = 100
  • M = 1
  • R = 2
  • P = 1

那么 C = floor((X-M)/R) = 49,cnt = ceiling((P - (X - M - C*R))/R) = 0.

Then C = floor((X-M)/R) = 49, and cnt = ceiling((P - (X - M - C*R))/R) = 0.

示例 2: 假设

  • X = 100
  • M = 1
  • R = 5
  • P = 12

那么 C = 19,cnt = 2.

Then C = 19, and cnt = 2.

示例 3: 假设

  • X = 101
  • M = 1
  • R = 5
  • P = 12

那么 C = 20,cnt = 3.

Then C = 20, and cnt = 3.

示例 4: 假设

  • X = 101
  • M = 2
  • R = 5
  • P = 12

那么 C = 19,cnt = 2.

Then C = 19, and cnt = 2.

因此,我们看到系统(M、R 和 P)和堆栈大小 (X) 都会影响 cnt.

Thus, we see that both the system (M, R, and P) and the stack size (X) affects cnt.

附带说明,启动 catch 需要多少空间并不重要.只要catch没有足够的空间,那么cnt就不会增加,所以没有外部影响.

As a side note, it does not matter how much space catch requires to start. As long as there is not enough space for catch, then cnt will not increase, so there are no external effects.

编辑

我收回我所说的关于 catch 的话.它确实发挥了作用.假设它需要 T 量的空间来启动.当剩余空间大于 T 时,cnt 开始递增,当剩余空间大于 T + P 时运行 println.这为计算增加了一个额外的步骤,进一步混淆了已经很混乱的分析.

I take back what I said about catch. It does play a role. Suppose it requires T amount of space to start. cnt starts to increment when the leftover space is greater than T, and println runs when the leftover space is greater than T + P. This adds an extra step to the calculations and further muddies up the already muddy analysis.

编辑

我终于有时间进行一些实验来支持我的理论.不幸的是,该理论似乎与实验不符.实际发生的情况非常不同.

I finally found time to run some experiments to back up my theory. Unfortunately, the theory doesn't seem to match up with the experiments. What actually happens is very different.

实验设置:具有默认 java 和 default-jdk 的 Ubuntu 12.04 服务器.Xss 从 70,000 开始,以 1 个字节递增到 460,000.

Experiment setup: Ubuntu 12.04 server with default java and default-jdk. Xss starting at 70,000 at 1 byte increments to 460,000.

结果位于:https://www.google.com/fusiontables/DataSource?docid=1xkJhd4s8biLghe6gZbcfUs3vT5MpS_OnscjWDbM我创建了另一个版本,其中删除了每个重复的数据点.换言之,仅显示与先前不同的点.这使得更容易看到异常.https://www.google.com/fusiontables/DataSource?docid=1XG_SRzrrNasepwZoNHqEAKuZlHiAm9vbEdwfsUA

The results are available at: https://www.google.com/fusiontables/DataSource?docid=1xkJhd4s8biLghe6gZbcfUs3vT5MpS_OnscjWDbM I've created another version where every repeated data point is removed. In other words, only points that are different from the previous are shown. This makes it easier to see anomalies. https://www.google.com/fusiontables/DataSource?docid=1XG_SRzrrNasepwZoNHqEAKuZlHiAm9vbEdwfsUA