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

2022-01-22 00:00:00 递归 stack stack-size java callstack

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

Today morning I answered a question which is related to StackoverflowException . The person has asked when Stackoverflow exception occurs

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

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

So my question is that is there any method by which we can compute the method call stacks size dynamically in our program and then applying a check before calling a method which checks whether method call stack has space to accommodate it or not to prevent StackOverflowException.

由于我是 java 人,我正在寻找 java,但也在寻找与该概念相关的解释,不受任何编程语言的限制.

As I am a java person I am looking for java but also looking for explanation related to the concept without boundation of any programming language.

推荐答案

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

The total memory available to a JVM is about 2-4GB for a 32bit JVM and the square of this for a 64bit JVM (about 4-16EB). The JVM splits it's memory into:

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

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

非堆内存

  • 聚合堆栈内存
    • 每线程堆栈内存(通过 JVM 选项 -Xss 控制的每线程分配):方法调用帧、参数、返回值、本地声明的原语和对对象的引用
    • aggregate stack memory
      • per-thread stack memory (per-thread allocation controlled via JVM option -Xss): method call frames, arguments, return values, locally declared primitives & references to objects

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

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

      1. Java SE/Java EE 中没有包含标准方法来获取每个线程堆栈的实际内存使用情况.
      2. 获取聚合非堆内存的标准方法:MemoryMxBean.getNonHeapMemoryUsage().引用 this 不允许您做出动态的代码内决策以避免 StackOverflow 异常
      3. 有一些标准方法可以在不占用内存的情况下获取调用堆栈:Thread.getStackTrace() ThreadMxBean.getThreadInfo() &ThreadInfo.getStackTrace()
      1. There's no standard method included in Java SE/Java EE to obtain the per-thread stack actual memory usage.
      2. There are standard methods to obtain the aggregate non-heap memory: MemoryMxBean.getNonHeapMemoryUsage(). Referring to this doesn't allow you to make dynamic in-code decisions to avoid StackOverflow exception
      3. There are standard methods to obtain the call stack without it's memory usage: Thread.getStackTrace() ThreadMxBean.getThreadInfo() & ThreadInfo.getStackTrace()

      我建议您不要按照问题中的建议进行操作,因为:

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

      • You can't do it without some complex JVM-specific API that instruments/introspects on dynamic thread stack memory usage - where will you find such an API??
      • The per-thread stack normally consumes a tiny amount of memory relative to the entire JVM, so it is usually easy to assign enough to suit your algorithm (e.g. default of 128KB stack size for Windows 64bit JVM whilst 2GB of memory might have been budgeted for the entire JVM)
      • It would be very limited in power: if your logic actually needed to call a method, but you couldn't due to insufficient memory, then your program would be broken at that point. A StackOverflow exception would actually be the best response.
      • What you are trying to do could be an anti-design anti-pattern.
        A "correct" approach would be to specify program requirements, specify required runtime environment (including minimum/needed memory!), and design your program accordingly for optimal performance and memory usage.

      一种反模式是在设计和开发过程中没有适当地考虑这些事情,只是想象一些运行时内省魔法可以解决这个问题.可能存在一些(罕见的!)高性能要求的应用程序,它们需要在运行时彻底重新排列算法以与发现的资源完全匹配 - 但这是复杂、丑陋的 &昂贵的.

      An anti-pattern is to not think about these things appropriately during design and development and just imagine some runtime introspection magic could cover for this. There may exist some (rare!) high-performance-demanding apps which need to drastically rearrange the algorithm at runtime to exactly match the discovered resources - but this is complex, ugly & expensive.

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

      And even then, it would probably be better drive dynamic algorithm changes at a macro-level from the "-Xss" parameter, rather than at a micro-level from the exact stack memory consumption at a location in code.

相关文章