`
xiangshouxiyang
  • 浏览: 50130 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

使用dubbo进行消费者端调用导致内存溢出问题排查

 
阅读更多

       公司某流程系统项目组出现内存溢出问题,场景是使用dubbo进行文件传输。首先,dubbo协议不适合进行文件传输,这个做法本身有问题,该项目组可能出于开发效率,历史原因等情况,使用了这样的技术方案。

        发生内存溢出的场景是 测试人员连续的上传一个144M大小的文件,在上传四五次后,出现内存溢出。web接收文件,通过dubbo传输给service端进行文件处理。web和service端设置堆内存都是1g。在没有并发的情况下,连续上传144M的文件不应该出现内存溢出。初步怀疑是发生的内存泄露导致文件占用的内存没有被回收。

        把项目组的代码down下来本地运行系统对场景进行复现。

        设置相关JVM参数便于观察现象和保留现场:

      

-XX:+PrintGCDetails
-Xmx1024m
-Xms1024m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D:/heapdump.hprof

       本地在连续上传五次这个144M的文件后,也出现了内存溢出。

 

      

java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3236)
	at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:113)
	at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
	at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:140)
	at org.springframework.util.StreamUtils.copy(StreamUtils.java:128)
	at org.springframework.util.FileCopyUtils.copy(FileCopyUtils.java:109)
	at org.springframework.util.FileCopyUtils.copyToByteArray(FileCopyUtils.java:156)
	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getBytes(StandardMultipartHttpServletRequest.java:291)
	at com.gforc.biz.controller.FileController.uploadFile(FileController.java:526)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)

        可以看到,web容器使用的是undertow,undertow在接受http请求时,是先把http请求内容存放在直接内存中,在需要读取http的formdata内容时,对于非文件内容,直接复制到堆内存中,对于文件内容,则以nio的方式把文件信息从直接内存拷贝到临时文件中,整个过程,堆内存都没有申请文件大小的内存空间。

 

       在controller层调用springmvc的MultipartFile的file.getBytes()时,申请了一个文件大小的字节数组内存空间来存放文件流信息,此时内存不足,导致内存溢出。

       再观察GC日志:

[GC (Allocation Failure) --[PSYoungGen: 280566K->280566K(316928K)] 733103K->733103K(1016320K), 0.0048276 secs] [Times: user=0.03 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 280566K->0K(316928K)] [ParOldGen: 452537K->329663K(699392K)] 733103K->329663K(1016320K), [Metaspace: 52711K->52711K(1097728K)], 0.0958676 secs] [Times: user=0.16 sys=0.00, real=0.10 secs] 
[GC (Allocation Failure) [PSYoungGen: 249872K->32K(286208K)] 841679K->591839K(985600K), 0.0033714 secs] [Times: user=0.05 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 254214K->220K(315904K)] 846021K->624795K(1015296K), 0.0139206 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 220K->0K(315904K)] [ParOldGen: 624575K->354325K(699392K)] 624795K->354325K(1015296K), [Metaspace: 52764K->52764K(1097728K)], 0.1000608 secs] [Times: user=0.19 sys=0.00, real=0.10 secs] 
[Full GC (Ergonomics) [PSYoungGen: 197604K->0K(315904K)] [ParOldGen: 616469K->583688K(699392K)] 814074K->583688K(1015296K), [Metaspace: 52764K->52764K(1097728K)], 0.1123836 secs] [Times: user=0.25 sys=0.00, real=0.11 secs] 
[GC (Allocation Failure) --[PSYoungGen: 280208K->280208K(315904K)] 863896K->929432K(1015296K), 0.0161663 secs] [Times: user=0.05 sys=0.00, real=0.02 secs] 
[Full GC (Ergonomics) [PSYoungGen: 280208K->0K(315904K)] [ParOldGen: 649224K->535404K(699392K)] 929432K->535404K(1015296K), [Metaspace: 52764K->52764K(1097728K)], 0.1258771 secs] [Times: user=0.33 sys=0.00, real=0.13 secs] 
[GC (Allocation Failure) [PSYoungGen: 131074K->32K(316416K)] 666479K->666508K(1015808K), 0.0250249 secs] [Times: user=0.08 sys=0.00, real=0.03 secs] 
[Full GC (Ergonomics) [PSYoungGen: 32K->0K(316416K)] [ParOldGen: 666476K->600940K(699392K)] 666508K->600940K(1015808K), [Metaspace: 52764K->52764K(1097728K)], 0.1091046 secs] [Times: user=0.22 sys=0.00, real=0.11 secs] 
[Full GC (Ergonomics) [PSYoungGen: 280433K->0K(316416K)] [ParOldGen: 600940K->478067K(699392K)] 881374K->478067K(1015808K), [Metaspace: 52765K->52765K(1097728K)], 0.1074561 secs] [Times: user=0.17 sys=0.00, real=0.11 secs] 
[GC (Allocation Failure) --[PSYoungGen: 250120K->250120K(316416K)] 728188K->859260K(1015808K), 0.0216361 secs] [Times: user=0.11 sys=0.00, real=0.02 secs] 
[Full GC (Ergonomics) [PSYoungGen: 250120K->0K(316416K)] [ParOldGen: 609139K->600946K(699392K)] 859260K->600946K(1015808K), [Metaspace: 52765K->52765K(1097728K)], 0.1163858 secs] [Times: user=0.30 sys=0.00, real=0.12 secs] 
[Full GC (Ergonomics) [PSYoungGen: 262146K->262144K(316416K)] [ParOldGen: 600946K->469724K(699392K)] 863092K->731868K(1015808K), [Metaspace: 52765K->52765K(1097728K)], 0.2965119 secs] [Times: user=0.92 sys=0.00, real=0.30 secs] 
[Full GC (Ergonomics) [PSYoungGen: 283648K->0K(316416K)] [ParOldGen: 618040K->469741K(699392K)] 901688K->469741K(1015808K), [Metaspace: 52786K->52786K(1097728K)], 0.1205818 secs] [Times: user=0.23 sys=0.00, real=0.12 secs] 
[GC (Allocation Failure) [PSYoungGen: 279648K->128K(316928K)] 749390K->600942K(1016320K), 0.0325090 secs] [Times: user=0.11 sys=0.00, real=0.03 secs] 
[Full GC (Ergonomics) [PSYoungGen: 128K->0K(316928K)] [ParOldGen: 600814K->600782K(699392K)] 600942K->600782K(1016320K), [Metaspace: 52788K->52788K(1097728K)], 0.2549737 secs] [Times: user=0.81 sys=0.00, real=0.25 secs] 
[Full GC (Ergonomics) [PSYoungGen: 262149K->262144K(316928K)] [ParOldGen: 600782K->467200K(699392K)] 862931K->729344K(1016320K), [Metaspace: 52788K->52598K(1097728K)], 0.2826828 secs] [Times: user=0.70 sys=0.00, real=0.28 secs] 
[Full GC (Ergonomics) [PSYoungGen: 278623K->0K(316928K)] [ParOldGen: 615516K->622978K(699392K)] 894139K->622978K(1016320K), [Metaspace: 52598K->52562K(1097728K)], 0.3579903 secs] [Times: user=0.98 sys=0.00, real=0.36 secs] 
[Full GC (Ergonomics) [PSYoungGen: 248317K->131072K(316928K)] [ParOldGen: 622978K->614786K(699392K)] 871295K->745858K(1016320K), [Metaspace: 52562K->52562K(1097728K)], 0.1744845 secs] [Times: user=0.44 sys=0.00, real=0.17 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 131072K->131072K(316928K)] [ParOldGen: 614786K->614707K(699392K)] 745858K->745779K(1016320K), [Metaspace: 52562K->52460K(1097728K)], 0.3197632 secs] [Times: user=0.92 sys=0.02, real=0.32 secs] 
java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:/heapdump.hprof ...

        通过GC日志可以发现,最后一个fullGC,老年代申请不到空间,导致了内存溢出。日志前面是新生代申请不到内存,触发fullGC,并把新生代存活的对象转移到老年代,老年代的存活对象不断增加,最终老年代内存不足。

       按道理,我连续的上传文件,在上传第二个文件时,第一个文件在堆内存的对象应该可以被JVM回收才对。可以发现,实际上JVM并没有办法回收文件对象。初步判定发生了内存泄漏。

       利用jdk自带的visualVM对内存溢出时保存的堆内存对象进行查看,



 
可以看到字节数组对象占了96.5%的内存。



 

可以看出来此时堆内存中的四个大小为151876120的对象就是我们上传的文件

       可以看出来,因为内存中的这四个文件对应的字节数组大内存对象没有被垃圾回收,导致内存溢出的发生。

       再看字节数组存在的引用,



 

       可以看出来,字节数组作为RPC接口的参数,被rpcContext的arguments属性和rpcInvocation的arguments属性引用,导致了字节数组无法被gc回收。可以看到,rpcContext被线程变量threadLocal引用。稍微熟悉dubbo的应该都清楚。rpcContext作为dubbo在rpc传输的上下文,经常被用来在dubbo消费者端和服务端之间通过线程变量,隐性的传递一些参数。

      由于使用dubbo的版本为2.5.7,翻阅dubbo源码,很快就看到dubbo自带的消费者端过滤器ConsumerContextFilter的代码:

/**
 * ConsumerContextInvokerFilter
 *
 * @author william.liangf
 */
@Activate(group = Constants.CONSUMER, order = -10000)
public class ConsumerContextFilter implements Filter {

    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        RpcContext.getContext()
                .setInvoker(invoker)
                .setInvocation(invocation)
                .setLocalAddress(NetUtils.getLocalHost(), 0)
                .setRemoteAddress(invoker.getUrl().getHost(),
                        invoker.getUrl().getPort());
        if (invocation instanceof RpcInvocation) {
            ((RpcInvocation) invocation).setInvoker(invoker);
        }
        try {
            return invoker.invoke(invocation);
        } finally {
            RpcContext.getContext().clearAttachments();
        }
    }

}
 RpcContext代码:

 

 

public RpcContext setInvocation(Invocation invocation) {
        this.invocation = invocation;
        if (invocation != null) {
            setMethodName(invocation.getMethodName());
            setParameterTypes(invocation.getParameterTypes());
            setArguments(invocation.getArguments());
        }
        return this;
    }
       通过上面代码可以看出,dubbo在每次消费者端调用服务端时,会把rpc调用的方法,参数等信息通过线程变量的方式记录下来,但在rpc调用完,只清除了rpcContext中的attachment属性。导致线程一直持有rpc调用传参的引用。

 

       在线程再次进行rpc调用时,线程变量会引用新的rpc调用的传参,旧的rpc调用传参就可被回收。由于dubbo本身使用于小数据量的传输,所以这种轻微的内存泄漏,在普通业务调用中并不会暴露出问题,但是在用来做文件传输时,特别是大文件传输时,问题就暴露出来了。       可以说,这是dubbo的一个bug,查看了github上dubbo的最新源码,发现该问题已被修复。在2019年5月23日提交的dubbo2.7.2版本代码中修复了该问题。dubbo2.7.2版本中ConsumerContextFilter代码:

 

@Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        RpcContext.getContext()
                .setInvoker(invoker)
                .setInvocation(invocation)
                .setLocalAddress(NetUtils.getLocalHost(), 0)
                .setRemoteAddress(invoker.getUrl().getHost(),
                        invoker.getUrl().getPort());
        if (invocation instanceof RpcInvocation) {
            ((RpcInvocation) invocation).setInvoker(invoker);
        }
        try {
            RpcContext.removeServerContext();
            return invoker.invoke(invocation);
        } finally {
            RpcContext.removeContext();
        }
    }
 可以看到,在代码的finally代码块中,把整个rpcContext清除了。即修复了该问题。

 

           内存泄漏的问题定位已经非常明确,要解决这个问题也显得很简单了。考虑升级dubbo框架可能会引入不必要的风险,针对该问题,我添加了一个dubbo过滤器RemoveRpcContextFilter,用于解决该问题。
package com.xxx.framework;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;

/**
 * dubbo消费服务后移除线程变量
 * dubbo当前2.5.7版本ConsumerContextFilter中通过RpcContext以线程变量的方式引用接口中的参数对象,且没有移除线程变量,导致参数无法被GC,
 * 只能在线程下次执行dubbo调用时线程变量指向新的参数对象的方式,让旧参数对象进行垃圾回收。这里手动清除线程变量,helpGC
 * dubbo适用于小数据传输,线程变量引用部分旧请求参数对象影响不大,该问题在dubbo 2019.5.23提交的2.7.2版本已修复。
 * Created by cd_huang on 2019/6/4.
 */
@Activate(group = Constants.CONSUMER, order = -10001)
public class RemoveRpcContextFilter implements Filter {

	public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
		try {
			return invoker.invoke(invocation);
		} finally {
			RpcContext.removeContext();
		}
	}
}
       然后在resouce目录下META-INF/dubbo目录下新建com.alibaba.dubbo.rpc.Filter文件,内容为
RemoveRpcContextFilter=com.xxx.framework.RemoveRpcContextFilter
          以dubbo的SPI机制注入该过滤器,使其生效。       
        本地验证后提交到测试,测试人员验证通过,即解决该问题。       
       使用dubbo进行文件传输这种做法本身就是有问题的。dubbo协议默认采用单一长连接进行NIO传输。在传输大文件网络传输过程,对导致该消费者端和服务端网络阻塞。dubbo配置使用多个连接可以一定程度上规避该问题。
      考虑到管理类流程类系统本身用量不大,基本不存在并发,以快速实现业务功能为主,暂时使用dubbo进行大文件传输,后续考虑其他方案。

 

 

 

 

 

 

  • 大小: 35.8 KB
  • 大小: 33 KB
  • 大小: 14.8 KB
  • 大小: 26.7 KB
分享到:
评论

相关推荐

    JAVA高级面试题包含Dubbo、JVM、Kafka等

    4. **内存泄漏检测**:如何使用VisualVM或JProfiler等工具进行监控和诊断。 接下来,Dubbo是阿里巴巴开源的一个分布式服务框架,面试中可能关注: 1. **服务注册与发现**:理解Zookeeper或Eureka等注册中心的工作...

    2024java面试宝典

    JVM:JVM部分涉及内存模型、内存空间的分配和回收、对象的初始化过程、内存溢出的原因及排查方法。还会问到垃圾回收算法和垃圾回收器的原理和配置,以及JVM调优方法,如何解决线上GC问题。 多线程与并发:多线程和...

    Cat技术入门总结

    - **异常记录**:自动记录并定位应用程序中的异常,提高问题排查效率。 - **系统状态监控**:收集系统运行环境的信息,帮助开发者和运维人员快速定位非代码因素引起的故障。 - **业务指标监控**:通过在关键业务...

    基于STM32蓝牙控制小车系统设计(硬件+源代码+论文)

    基于STM32蓝牙控制小车系统设计(硬件+源代码+论文)

    某汽车联合车间工艺布置图.zip

    某汽车联合车间工艺布置图.zip

    统计学中的因果推断.pdf

    统计学中的因果推断

    轻量级的PHP地址发布页源码.zip

    1:后台登录地址为/admin/login.php,提供便捷的配置入口。 2:默认用户名是admin,密码为password123,首次登录后可。 3:使用方法:上传到虚拟机或服务器并解压,访问首页查看效果, 4:进入后台可编辑3个固定修改链接、添加或删除额外链接、设置底部文字及选择模板。 5:底部文字通过转义处理,不支持HTML,确保输出安全。 6:无论是个人项目还是分享导航,LinkEase都提供简单的解决方案。

    blast_furnace_front_on.png

    blast_furnace_front_on

    wither_rose.png

    j

    h5py-3.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

    该资源为h5py-3.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl,欢迎下载使用哦!

    【数字图像处理】形态学处理与纹理分析技术:边界提取、孔洞填充及组件标记的应用研究

    内容概要:本文档是关于数字图像处理课程作业的报告,主要分为两个部分:形态学处理和纹理分析。形态学处理部分涵盖边界提取、孔洞填充和组件标记三个任务,详细描述了每个任务的具体步骤和方法,如通过形态学方法找到白色图案的内部区域并进行边界提取,利用连通分量标记技术进行孔洞填充,以及采用4邻接和8邻接方式对对象进行组件标记。纹理分析部分则介绍了使用Law's方法获取特征向量的过程,包括卷积和能量计算,还展示了如何用K-means算法对像素进行分类,并提出了一些改进措施,如调整窗口大小、优化K值选择等。 适合人群:具有图像处理基础知识的学生或研究人员,特别是正在学习数字图像处理课程的人士。 使用场景及目标:①帮助学生理解形态学处理的基本概念和技术,如边界提取、孔洞填充和组件标记;②指导学生掌握纹理分析的方法,如Law's方法和K-means聚类算法的应用;③通过实例操作提高学生的实践能力和问题解决能力。 阅读建议:此文档为课程作业报告,内容较为具体和技术化,建议读者先了解基本的形态学处理和纹理分析理论,再结合文档中的具体步骤进行实践操作,以便更好地理解和掌握相关知识。

    MP0 Set up xv6.pdf操作系统基于Docker和QEMU的xv6环境搭建与简单进程通信实验:教学操作系统实践

    内容概要:本文介绍了如何设置xv6操作系统的学习环境。xv6是MIT创建的一个用于教学的类Unix内核示例。文章首先解释了为什么选择Docker作为虚拟化工具,强调了其轻量级的特点,并指导读者安装Docker。接着详细描述了从克隆GitHub仓库到加载Docker镜像的具体步骤,以及如何使用QEMU模拟器在非RISC-V架构上启动xv6。最后提供了一个简单的练习,要求编写一个名为detective的程序,利用UNIX系统调用来查找特定名称的文件,并通过管道在父子进程间通信。 适合人群:具备一定C语言编程能力和系统编程经验的学生或开发者,尤其是对操作系统原理感兴趣的人士。 使用场景及目标:①学习Docker的安装与配置,理解容器化技术的优势;②掌握xv6内核的基本操作,包括编译和运行;③通过完成detective程序,深入理解进程管理、文件系统遍历和进程间通信等操作系统核心概念。 阅读建议:建议读者按照文档逐步实践,确保每一步都能成功执行。由于部分命令和工具基于Linux平台,推荐在Linux环境下进行操作。此外,在动手之前先阅读xv6参考书籍的第一章,有助于更好地理解和完成练习。

    糖化、水罐及CIP工艺流程.rar

    糖化、水罐及CIP工艺流程.rar

    activator_rail_on.png

    activator_rail_on

    液压剪式升降平台(step SolidWorks)设计.rar

    液压剪式升降平台(step SolidWorks)设计.rar

    【操作系统领域】HarmonyOS的Linux内核子集(LOS)技术解析:智能设备核心支撑与未来发展趋势

    内容概要:本文详细介绍了HarmonyOS及其Linux内核子集(LOS)。HarmonyOS是华为自主研发的面向全场景的分布式操作系统,旨在打破国外操作系统垄断,推动国产操作系统发展。LOS作为HarmonyOS的重要组成部分,位于内核层,负责管理硬件资源、内存、文件系统和网络等。LOS具有虚拟内存管理、进程隔离、强大的网络支持、高效的文件系统、多线程编程支持和任务调度机制等技术特点。LOS在智能手机、智能家居设备和智能穿戴设备等领域发挥了重要作用,确保了系统的性能、稳定性和低功耗。与Linux原生内核和鸿蒙微内核相比,LOS在功能特性、性能表现和适用场景上有明显优势,并且与鸿蒙微内核协同工作,共同推动HarmonyOS的发展。未来,LOS将在安全性、性能优化和新功能支持等方面取得更大突破,推动HarmonyOS生态的繁荣发展。 适合人群:对操作系统底层技术感兴趣的开发者、科技爱好者以及从事智能设备相关领域的工程师。 使用场景及目标:①深入了解HarmonyOS及其内核子集(LOS)的技术特点和应用场景;②为开发基于HarmonyOS的智能设备提供理论支持和技术参考;③探索LOS在不同智能设备中的优化和应用,推动智能设备的创新和发展。 其他说明:本文不仅介绍了LOS的技术细节,还探讨了其与鸿蒙微内核的区别和协同工作方式,以及对未来发展的展望。这有助于读者全面理解HarmonyOS的内核架构和技术优势,为未来的开发和研究提供指导。

    第三章习题作业.docx

    第三章习题作业.docx

    openssl-3.5.0-multiple-Kylin-Server-V10-GFB-arm64.tar.gz

    为了解决信创环境下不能连网,因此在Kylin Server V10 下编译了openssl最新版本,而且做成了离线安装的脚本,安装步骤如下所示: 1. 解压软件包 [root@daolian ~]# tar -zxvf openssl-3.5.0-202504152120-multiple-Kylin-Server-V10-GFB-arm64.tar.gz 2. 查看目录中内容 [root@daolian nginx]# ls openssl.tar.gz setup.sh 3.安装 [root@daolian openssl]# ./setup.sh OPENSSL 3.5.0 INSTALL Sucesses 4.查看版本号 root@daolian:~# openssl version -a OpenSSL 3.5.0 8 Apr 2025 (Library: OpenSSL 3.5.0 8 Apr 2025) built on: Tue Apr 15 12:43:51 2025 UTC platform: linux-aarch64 options: bn(64,64)

    模具-Φ146.6药瓶注塑模设计.zip

    模具-Φ146.6药瓶注塑模设计.zip

    h5py-3.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

    该资源为h5py-3.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl,欢迎下载使用哦!

Global site tag (gtag.js) - Google Analytics