您的位置:首页 > 房产 > 家装 > 微信短网址生成器_宁波小程序网络开发公司_软文大全500篇_公司企业网站建设方案

微信短网址生成器_宁波小程序网络开发公司_软文大全500篇_公司企业网站建设方案

2025/4/5 5:55:16 来源:https://blog.csdn.net/heeheeai/article/details/147000123  浏览:    关键词:微信短网址生成器_宁波小程序网络开发公司_软文大全500篇_公司企业网站建设方案
微信短网址生成器_宁波小程序网络开发公司_软文大全500篇_公司企业网站建设方案

MemoryWorkspace 是 ND4J 中一个强大的内存管理机制,旨在显著提高性能并减少 Java 垃圾回收 (Garbage Collection, GC) 的开销。在深度学习和科学计算中,经常会创建大量临时的 INDArray 对象(ND4J 中的 N 维数组)。如果依赖标准的 Java GC 来管理这些对象的内存(尤其是堆外内存 Off-Heap Memory),频繁的 GC 暂停会严重影响性能。

MemoryWorkspace 通过以下方式解决这个问题:

  1. 预分配内存块: 它预先分配一大块内存(可以在 Java 堆上 On-Heap,但更常用的是在堆外 Off-Heap)。
  2. 作用域内分配: 在一个特定的 MemoryWorkspace 作用域 (scope) 内创建的所有 INDArray,它们的内存会从这个预分配的内存块中获取,而不是通过标准的分配流程。
  3. 快速释放/重用: 当离开 MemoryWorkspace 的作用域时(通常通过 try-with-resources 语句),该工作空间内分配的所有 INDArray 所占用的内存会被一次性标记为可重用,或者整个内存块被释放(取决于配置)。关键在于,这个过程绕过了对每个单独 INDArray 的 Java GC。这使得内存的“回收”非常快。

为什么需要 MemoryWorkspace?(Why Needed?)

  • 减少 GC 开销: 这是最主要的原因。避免了 JVM 对大量短暂 INDArray 对象进行垃圾回收的需要,从而减少了 GC 暂停时间,提高了计算的流畅度和整体吞吐量。
  • 提高分配速度: 从预分配的连续内存块中获取小块内存通常比系统调用或标准 JVM 分配更快。
  • 减少内存碎片: 尤其对于堆外内存,有助于更有效地管理和减少碎片。
  • 更可预测的性能: 减少了由 GC 引起的不可预测的性能抖动。

最常见和推荐的使用方式是结合 Java 的 try-with-resources 语句,这能确保工作空间在使用完毕后被正确关闭(内存被标记为可重用)。

import org.nd4j.linalg.api.buffer.DataType
import org.nd4j.linalg.api.memory.conf.WorkspaceConfiguration
import org.nd4j.linalg.api.memory.enums.AllocationPolicy
import org.nd4j.linalg.api.memory.enums.LearningPolicy
import org.nd4j.linalg.api.memory.enums.SpillPolicy
import org.nd4j.linalg.api.ndarray.INDArray
import org.nd4j.linalg.factory.Nd4j
import org.nd4j.linalg.ops.transforms.Transformsobject WorkspaceExample {@JvmStaticfun main(args: Array<String>) {// 1. 配置工作空间 (可选,可以使用默认配置)val wsConfig: WorkspaceConfiguration = WorkspaceConfiguration.builder().initialSize((100 * 1024 * 1024).toLong()) // 初始大小 100MB.maxSize((500 * 1024 * 1024).toLong()) // 最大大小 500MB (如果需要增长).policyAllocation(AllocationPolicy.STRICT) // 分配策略: STRICT (空间不足时报错).policyLearning(LearningPolicy.OVER_TIME) // 学习策略: NONE (不自动调整大小).policySpill(SpillPolicy.FAIL) // 溢出策略: FAIL (空间不足时失败).build()// 定义工作空间名称val workspaceId = "MyCalculationWorkspace"// 2. 使用 try-with-resources 激活并使用工作空间try {Nd4j.getWorkspaceManager().getAndActivateWorkspace(wsConfig, workspaceId).use { ws ->// 在这个 try 块内创建的 INDArray 会使用 'MyCalculationWorkspace' 的内存val x: INDArray = Nd4j.rand(DataType.FLOAT, 1000, 1000) // 分配在工作空间内val y: INDArray = Nd4j.rand(DataType.FLOAT, 1000, 1000) // 分配在工作空间内println("X is allocated in workspace: " + x.isAttached) // 输出 trueprintln("Current workspace size: " + ws.currentSize)// 计算结果 z 也会分配在当前活动的工作空间内val z = x.mmul(y)println("Z is allocated in workspace: " + z.isAttached) // 输出 trueprintln("Workspace size after mmul: " + ws.currentSize)// 在这里可以进行更多的计算...val w = z.add(1.0) // w 也在工作空间内}} catch (e: Exception) {e.printStackTrace()}// 在 try 块外部,之前在工作空间中创建的 x, y, z, w 变量引用的是无效内存// 尝试访问它们通常会导致错误或未定义行为 (除非使用了 detach/leverage)// System.out.println(x); // !!! 危险操作 !!!// 如果需要一个不受工作空间影响的数组val outsideArray: INDArray = Nd4j.create(DataType.FLOAT, 10, 10) // 在工作空间外部创建,由 GC 管理println("Outside array is attached to workspace? " + outsideArray.isAttached) // 输出 false// 清理 (如果需要手动管理)
//         Nd4j.getWorkspaceManager().destroyAllWorkspacesForCurrentThread();}// 从工作空间返回数组fun calculationWithResult(input: INDArray): INDArray {Nd4j.getWorkspaceManager().getAndActivateWorkspace("ResultWorkspace").use { ws ->val tempResult = input.mul(2.0) // 在工作空间内val finalResult = tempResult.add(1.0) // 仍在工作空间内// 使用 detach() 将数组从工作空间中移出,使其生命周期由 GC 管理// detach() 会创建一个新的 INDArray (或只是改变其状态),其数据复制到常规内存中return finalResult.detach()}// finalResult 在这里是有效的,因为它被 detach 了}// 在迭代中使用工作空间 (例如 RNN)fun iterativeTask(): INDArray {var state: INDArray = Nd4j.zeros(DataType.FLOAT, 1, 10) // 初始状态在外部val iterWs = "IterativeWS"// 配置一个可重用的工作空间val iterConfig: WorkspaceConfiguration = WorkspaceConfiguration.builder().initialSize((10 * 1024 * 1024).toLong()) // 10MB.policyLearning(LearningPolicy.FIRST_LOOP) // 让它在第一次循环时学习所需大小.build()for (i in 0..99) {Nd4j.getWorkspaceManager().getAndActivateWorkspace(iterConfig, iterWs).use { ws ->val input: INDArray = Nd4j.rand(DataType.FLOAT, 1, 10) // 本次迭代的输入,在工作空间内// 使用 leverage() 将上一次迭代的结果 (state) "带入" 当前工作空间作用域// leverage() 不会复制数据,它假设 state 的数据在下一次循环开始时// 仍然位于同一个工作空间内存区域(因为工作空间会被重用)// 如果 state 是第一次进入或者来自外部,leverage 可能会触发复制val prevState = state.leverage()state = Transforms.tanh(prevState.add(input))}}// 循环结束后,最终的 state 仍然指向工作空间内存。// 如果需要长期保留它,需要 detach()return state.detach()}
}

关键方法和概念:

  • Nd4j.getWorkspaceManager().getAndActivateWorkspace(…): 获取(如果不存在则创建)并激活一个工作空间。通常在 try-with-resources 中使用。
  • INDArray.isAttached(): 检查一个 INDArray 当前是否附加到某个活动的工作空间。
  • INDArray.detach(): 创建一个 INDArray 的副本(或仅改变其状态),该副本位于常规内存中(由 GC 管理),不再受工作空间生命周期影响。当需要将工作空间中的计算结果返回或传递到工作空间作用域之外时,必须使用它。
  • INDArray.leverage(): 将一个 INDArray 标记为可以在同一个工作空间的下一个周期(下一次激活)中使用。这在迭代计算(如 RNN 或优化循环)中非常有用,可以避免在每次迭代时都将状态 detach() 再重新引入的开销。它假设工作空间的内存在不同周期之间会被重用。
  • 嵌套工作空间 (Nested Workspaces): 可以在一个工作空间内打开另一个工作空间。内部工作空间可以有自己的内存,也可以配置为在空间不足时“溢出”到父工作空间。

配置选项 (WorkspaceConfiguration)

  • initialSize: 工作空间初始分配的内存大小。
  • maxSize: 工作空间可增长到的最大大小(如果 AllocationPolicy 或 SpillPolicy 允许增长)。
  • policyAllocation (AllocationPolicy):
    • STRICT: 如果请求的内存超过当前可用空间,则失败。
    • OVERALLOCATE: 允许分配超过 initialSize 的内存,但通常不超过 maxSize。
  • policySpill (SpillPolicy): 当工作空间内存不足时如何处理:
    • FAIL: 抛出异常。
    • REALLOCATE: 尝试重新分配更大的内存块(可能很慢)。
    • EXTERNAL: 临时在工作空间外部(常规内存)分配。
  • policyLearning (LearningPolicy): 自动调整工作空间大小的策略:
  • NONE: 不自动调整。
    • FIRST_LOOP: 根据第一次激活周期内的峰值内存使用量来调整 initialSize。
    • OVER_TIME: 在多个周期内动态调整大小(更复杂)。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com