计算方法调用堆栈大小以检查StackOverflowException

Nik*_*wal 10 java recursion stack callstack stack-size

今天早上我回答了一个与StackoverflowException相关的问题.该人询问何时发生Stackoverflow异常

查看此链接在C#,C++和Java中导致堆栈溢出的最简单方法

所以我的问题是,有没有任何方法可以在程序中动态计算方法调用堆栈大小,然后在调用方法之前应用检查,该方法检查方法调用堆栈是否有空间来容纳它,以防止StackOverflowException.

因为我是一个java人,我正在寻找java,但也寻找与概念相关的解释,没有任何编程语言的限制.

Gle*_*est 9

对于32位JVM,JVM可用的总内存大约为2-4GB,而对于64位JVM(大约4-16EB),其大小为4.JVM将其内存分为:

  1. 堆内存(通过JVM选项-Xms和-Xmx控制分配)

    • 构造的对象和数组实例
    • 静态类和数组数据(包括包含的对象/数组实例)
    • 线程实例(对象实例,运行时数据和元数据,包括线程对象监视器锁定引用)
  2. 非堆内存

    • 聚合堆栈内存
      • 每线程堆栈内存(通过JVM选项-Xss控制的每线程分配):方法调用帧,参数,返回值,本地声明的原语和对象的引用
    • 静态常量(原语)
    • 字符串实例池
    • java代码:加载的类和元数据
    • JVM内部使用内存(JVM代码和数据结构)

请参阅http://docs.oracle.com/javase/7/docs/api/java/lang/management/MemoryMXBean.htmlhttp://www.yourkit.com/docs/kb/sizes.jsp

有没有什么方法可以在我们的程序中动态计算方法调用堆栈的大小

  1. Java SE/Java EE中没有包含标准方法来获取每线程堆栈的实际内存使用情况.
  2. 有一些标准方法可以获取聚合非堆内存:MemoryMxBean.getNonHeapMemoryUsage().参考此内容不允许您进行动态的代码内决策以避免StackOverflow异常
  3. 有一些标准方法可以在没有内存使用的情况下获取调用堆栈: Thread.getStackTrace() ThreadMxBean.getThreadInfo()&ThreadInfo.getStackTrace()

我建议您不要在问题中做出建议,因为:

  • 如果没有一些复杂的特定于JVM的API来监视动态线程堆栈内存的使用,你就无法做到 - 你会在哪里找到这样的API?
  • 每个线程堆栈通常相对于整个JVM消耗少量内存,因此通常很容易分配足以满足您的算法(例如,对于Windows 64位JVM,默认为128KB堆栈大小,而2GB内存可能已预算为整个JVM)
  • 它的功率非常有限:如果你的逻辑实际上需要调用一个方法,但由于内存不足你就不能,那么你的程序就会被打破.一个StackOverflow例外实际上是最好的回应.
  • 你想要做的可能是一个反设计的反模式.
    "正确"的方法是指定程序要求,指定所需的运行时环境(包括最小/所需的内存!),并相应地设计程序以获得最佳性能和内存使用.

    反模式是在设计和开发过程中不要适当考虑这些事情,只是想象一下运行时内省魔术可以涵盖的内容.可能存在一些(罕见的)高性能要求的应用程序,这些应用程序需要在运行时彻底重新排列算法以与发现的资源完全匹配 - 但这是复杂,丑陋和昂贵的.

    即便如此,从"-Xss"参数驱动宏观级别的动态算法更改可能会更好,而不是代码中某个位置的精确堆栈内存消耗的微观级别.


小智 5

我希望我猜你真正在问什么.起初我以为你在问你的电话会有多少电话.换句话说,根据您当前的方法情况,我认为您想知道触发此异常的可能性有多大.然后我决定你真的想知道你需要多少叠加深度.在这种情况下,这里有另一个堆栈溢出问题似乎解决了这个问题. java调用堆栈的最大深度是多少?

这告诉您如何将其设置为java命令行参数(对于java,而不是您的程序).

无论哪种方式,我都想指出,当我进行无休止的递归时,堆栈溢出主要发生在我身上.我写过自己的方法(当然是错误的),并且当问题得到解决时意味着停止,但不知怎的,终止条件从未到达.这会将方法调用反复放到堆栈中,直到超出最大值.不是我的想法.

我希望有所帮助.