首页 > 解决方案 > MemoryStack#stackMalloc 和 MemoryStack stack = stackPush(); 有什么区别?堆栈.malloc?

问题描述

我只是想知道有什么区别,什么更鼓励,MemoryStack#stackMalloc以及其他静态stackXx方法和try (var stack = stackPush()) { stack.malloc }模式?

我认为他们也这样做。只有stackPush你可以有多个堆栈?

标签: lwjgl

解决方案


静态方法MemoryStack.stackMalloc(int)MemoryStack.stackCalloc(int)(以及它们的特化返回, IntBuffer,LongBufferFloatBufferLWJGL DoubleBuffer3's PointerBuffer)首先调用MemoryStack.stackGet()以检索(并可能初始化)线程局部变量TLS(在当前实现中)以检索当前线程的 MemoryStack 实例,然后调用实例方法 MemoryStack.malloc(int)MemoryStack.calloc(int)或该 Thread-Local MemoryStack 实例上的任何类型特化。

重复执行此操作将慢慢导致当前线程的 MemoryStack 实例中的“堆栈”内存耗尽,进一步调用引发OutOfMemoryErrorJava 异常。因此,如果您使用静态方法分配内存malloc/calloc(int),并且不执行任何其他操作,例如通过实例方法重置当前(且唯​​一)堆栈帧的堆栈指针MemoryStack.setPointer(int)以“回收”为该 MemoryStack 分配的内存,那么这个 MemoryStack 实例很快就会耗尽内存。

静态方法MemoryStack.stackPush()还对调用线程的 MemoryStack 实例进行 Thread-Local 查找(如果当前线程尚未初始化,则可能进行初始化),然后调用实例方法MemoryStack.push()以创建新的“堆栈帧”。

从该MemoryStack.push()方法的JavaDocs:

存储当前堆栈指针并将新帧推入堆栈。在进行任何堆栈分配之前,应在进入方法时调用此方法。退出方法时,调用 pop() 方法恢复之前的栈帧。

可以嵌套成对的 push/pop 调用。必须注意:

  • 将每次推送都与流行音乐相匹配
  • 在至少调用一次 push 之前不调用 pop
  • 不将推送调用嵌套到超过最大支持深度

所以,我们看到这MemoryStack.push()将创建一个新的“堆栈帧”,它基本上就是当前指针的位置。随后MemoryStack.pop()将弹出当前堆栈帧从帧列表/堆栈中弹出,并将 MemoryStack 的指针重置为先前的位置(在调用 push() 之前它具有)。

现在,MemoryStack 类的设计使得它可以通过实现接口与try-with-resources Java 语句(它本身已在 Java 7 中引入)一起使用java.lang.AutoCloseable。MemoryStack 方法的实现close()只需pop()thisMemoryStack 实例执行一个操作,以便弹出当前“堆栈帧”并将 MemoryStack 的指针重置为前一个/父堆栈帧的值(可能是第一个/默认帧) .

因此,您想要比较的不同方法确实做了不同的事情:

  1. MemoryStack.malloc(int)没有 MemoryStack 的 push/pop 将增加 MemoryStack 的指针
  2. MemoryStack.stackPush()因为 try-with-resources 语句中的资源将创建一个新的“堆栈帧”,以便相应的MemoryStack.pop()调用可以“回收”分配的内存(即碰撞指针与前一帧的差异)

本质上,您应该始终 push(),分配内存,然后 pop(),以便在您的应用程序中获得合适的分配“框架”。您可以使用 try-with-resources Java 语句(或手动执行)来执行此操作。

此外,我想向您指出有关“LWJGL 中的内存管理”的 LWJGL 3 博客文章,其中包含有关不同分配策略及其在某些情况下的优缺点的更多有用信息。

最后,您帖子中的问题:

只有stackPush你可以有多个堆栈?

可以这样回答,是的,您可以通过以下任一方式拥有不同的 MemoryStack 实例:

  • 自己分配那些 MemoryStack 实例(没有什么能阻止你调用MemoryStack.create()或它的重载之一
  • 使用多个线程,当使用静态 MemoryStack 方法时,每个线程将获得自己的 MemoryStack 实例,该方法将对MemoryStack.stackGet().

但是,您可能并不真正需要每个线程多个 MemoryStack 实例,因为根据 MemoryStack 的“性质”,它应该或多或少类似于 Java 方法调用的调用堆栈,根据定义,这只是在每个线程中发生。


推荐阅读