递归代码在Unix系统上运行缓慢,但在Windows上快速。

4

我有一段Java代码,其中包含while循环和递归。我们面临的问题是,在Unix服务器上调用下面的方法所需的时间几乎比Windows服务器上要慢8倍。有没有什么想法可以改进Unix服务器上的执行时间呢?我们正在使用JDK 1.6_43 [64位]。

protected Date abc(int n, Date date) 
{
    long tStart = System.currentTimeMillis();

    if (n > 0) 
    {
          while (n > 0)
          {
                --n;
                date = getNextExchangeDateUnadjusted(date);
          }

          return date;
    }
    else 
    {

          Date nextExchangeDate = getNextExchangeDateUnadjusted(date);

          Date previousExchangeDate = getNextExchangeDateUnadjusted(date);

          while (!abc( -n + 1, previousExchangeDate).equals(nextExchangeDate)) 
          {

                date = date.addDays( -14);

                previousExchangeDate = getNextExchangeDateUnadjusted(date);

          }

          return previousExchangeDate;
    }
}

编辑:

以下是调用上述getNextExchangeDateUnadjusted方法的代码

public Date getNextExchangeDateUnadjusted(Date date) {
    // Third Wednesday of each month
    Date thirdWednesdayInMonth = date.getThirdWednesdayInMonth();
    if (thirdWednesdayInMonth.after(date)) {     
      return thirdWednesdayInMonth;
    }
    return date.addMonths(1).getThirdWednesdayInMonth();
  }
}

此外,我想补充的是代码在这一部分花费的时间最长:
      while (!abc( -n + 1, previousExchangeDate).equals(nextExchangeDate)) 
      {

            date = date.addDays( -14);

            previousExchangeDate = getNextExchangeDateUnadjusted(date);

      }

编辑2:

随着进程的进行,我们在Unix服务器上进行了多次堆转储,并发现'Retained Heap'从约1mb增长到4.5mb,因此堆栈大小显著增加。不确定是否会导致性能变慢。我们现在将在Windows上进行堆转储,并尝试使用XSS更改堆栈大小。


3
请问您需要翻译成什么语言呢? - Davide Lorenzo MARINO
似乎在处理日期对象时存在问题。也许可以一直使用“long”进行所有计算,直到最后? - Philipp Sander
@DavideLorenzoMARINO:我很快会发布代码。 - Lokesh
1
你使用的是哪种日期类型?(date.getThirdWednesdayInMonth()?) - Thierry
@Thierry:我们有自己的日期类,但基本上它只提供一些实用工具,并在内部仅使用java.util.Date。 - Lokesh
显示剩余4条评论
2个回答

1
采用了多种方法来解决此问题:
  1. 我们排除了任何IO或远程调用导致的不必要延迟。
  2. 通过Visual VM获取堆转储以查看进程中的任何异常行为,并在Unix和Windows之间进行比较。我们发现在这里,主线程占用了4.5mb的堆栈空间,但在Unix和Windows中都是相同的。
  3. 现在唯一的选择是查看Unix和Windows上JVM之间是否存在差距以及两者之间是否存在优化差距。

问题分为3部分,当我们运行命令java -version时发现了差距。

  • 在Windows上

    Java版本号为 "1.6.0_43"

    Java(TM) SE运行环境版本为(build 1.6.0_43-b01)

    Java HotSpot(TM) 64位服务器虚拟机版本为(build 20.14-b01, 混合模式)

  • 在Unix上

    Java版本号为 "1.6.0_43"

    Java(TM) SE运行环境版本为(build 1.6.0_43-b01)

    Java HotSpot(TM) 64位服务器虚拟机版本为(build 20.14-b01, 解释模式)

您可以在JVM热点模式下看到Unix和Windows之间的明显差异。进一步调查发现,运行在“解释”模式下的JVM不会优化代码[本文有详细信息:https://blog.codecentric.de/en/2012/07/useful-jvm-flags-part-1-jvm-types-and-compiler-modes/]。因此,我们在Unix上使用标志-Xmixed开始了我们的过程,强制JVM工作在混合模式下。这解决了我们的问题,Unix和Windows的性能变得相同。
编辑:
由于Unix系统中的参数-Djava.compiler=NONE,JVM被推入了解释模式。

但是有人一定强制使用了“解释模式”,因为“混合模式”被选择为默认模式。列出“-X”选项,显示“-Xmixed 混合模式执行(默认)”。 - SubOptimal
是的,没错,这是由于遗留代码中的参数:-Djava.compiler=NONE引起的。这会将jvm推入解释器模式。我会更新答案。 - Lokesh

-1
我建议你先拿笔纸把代码的逻辑确定好。
我已经为你做了以下工作。
assume abc is initially called as abc(1, "date < 3th Wednesday")
it will return "3th Wednesday in the same month"

assume abc is initially called as abc(0, "date < 3th Wednesday")
1. while loop iteration
abc(1, 3th Wednesday in the same month)
  - return 3th Wednesday of month+1
- as this is not equal with the "3th Wednesday in the same month"
   (nextExchangeDate) you compute "date - 14 day"
2. while loop iteration abc will be called as abc(1, "date - 14 day")
which return "3th Wednesday of month-1"
3. while loop iteration abc will be called as abc(1, "3th Wednesday of month-1")
...

我在这里停下了。这似乎更像试错而不是计算。在寻找性能差异之前,我会先修复它。

好的,这里有一个计算的例子

起始日期为“2015年11月16日”,n = 1

abc(1, 16.11.2015)
16.11.2015 get 3th Wed ==> 18.11.2015
abc date: 18.11.2015

设开始日期为"2015年11月16日",n = 0

abc(0, 16.11.2015)
16.11.2015 get 3th Wed ==> 18.11.2015
16.11.2015 get 3th Wed ==> 18.11.2015
abc(1, 18.11.2015)
18.11.2015 get 3th Wed ==> 18.11.2015
18.11.2015 + (1) month
18.12.2015 get 3th Wed ==> 16.12.2015
16.11.2015 + (-14) days
02.11.2015 get 3th Wed ==> 18.11.2015
abc(1, 18.11.2015)
18.11.2015 get 3th Wed ==> 18.11.2015
18.11.2015 + (1) month
18.12.2015 get 3th Wed ==> 16.12.2015
02.11.2015 + (-14) days
19.10.2015 get 3th Wed ==> 21.10.2015
abc(1, 21.10.2015)
21.10.2015 get 3th Wed ==> 21.10.2015
21.10.2015 + (1) month
21.11.2015 get 3th Wed ==> 18.11.2015
abc date: 21.10.2015 (the 3th Wed of previous month)

我不相信没有更好的方法来计算它。


代码运行正常,问题在于性能。这是遗留的东西,更改它对我们来说是最后的选择。问题是为什么它在Windows上运行得更快? - Lokesh
@Lokesh 对于简单的日期计算,不应该有太大的差异。 - SubOptimal
我们有证据表明存在差异。我们的进程在生成数据文件时调用此方法,在 Windows 中,该进程需要5分钟,而在 Unix 中,则需要30到40分钟。这是使用相同的代码。 - Lokesh
@Lokesh 你确定调用abc()方法会浪费时间吗?即使是发布的代码,计算也不应该需要五分钟。你能提供一个需要那么长时间的daten的例子吗?在所提到的abc()方法循环中是否涉及其他代码? - SubOptimal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接