`
cyj86
  • 浏览: 4092 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java加载dll,导致Java进程内存泄露

阅读更多
By zhaoch
在做网络监控系统的性能测试时,出现了内存泄露的问题,困扰了很久,现在终于算是解决了,但是根本原因尚不明确,拿出来大家讨论下,看看能不能完美解决~

这个问题奇怪的地方在于是Java进程内存泄露,而不是平常的JVM内存泄露,用Jprofile等工具也无法看出问题所在。

测试代码如下:
        System.loadLibrary("test1");

        int threadPoolSize = 400;
        ExecutorService service = Executors.newFixedThreadPool(threadPoolSize);

        for (int i = 0; i < 400; i++) {
            service.submit(new Runnable() {
                public void run() {
                    while (true) {
                        try {
                            Thread t = new Thread();
                            t.start();
                            Thread.sleep(100);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }


说明:此段代码所做的工作就是加载一个dll,然后不断的启动线程(线程什么也不做,直接终止)。
注:线程池只是为了加速问题复现,无其他用处。

现象:
1.如果不加载dll,只不断的启动线程,Java进程内存正常,不会一直增长。
2.如果加载附件中test1的dll,Java进程内存会一直增长。
3.如果加载附件中test2的dll(需要安装C++运行环境vcredist_x86),Java进程内存正常,不会一直增长。

dll说明:
dll的工程源码在附件中,test1和test2的区别只在于编译选项,如附件:test1选择的是“使用标准Windows库”或“在静态库中使用MFC”,test2选择的是“在共享DLL中使用MFC”
此dll工程的特点在于使用了jni,并引入了mfc头文件【#include <afxwin.h>】,如果不引入mfc头文件则不会引起内存泄漏


目前此问题的根本原因尚不明确,怀疑是jdk的bug(使用最新的jdk1.6.0.23也没用),不知道大家有什么想法吗?欢迎大家讨论~



  • 大小: 22.5 KB
分享到:
评论
34 楼 flyiclj 2011-06-30  
wangyazhen 写道
建议先对dll中的方法进行压力测试 推荐.Net memory profiler工具
然后在使用Jprofiler对你的java应用程序进行跟踪
不管是java还是微软的代码 要想高效、及时的回收内存,需要在对象释放的时候显示地切掉与外部的引用,不然可能垃圾要回收好几次才能回收掉


dll的压力测试没有做过,不过这个核心程序ping.cpp是网上的开源代码,已经好多年,看历史可以看出从98年开始,这么长的时间如果有问题,应该早就发现了吧
Jprofiler也只能跟踪JVM的内存使用吧,这个程序是进程内存泄露,JVM内存的使用是正常的,在JProfiler看不出什么问题

个人感觉还是因为JNI加载dll,才导致了Java进程内存泄露
33 楼 wangyazhen 2011-06-29  
建议先对dll中的方法进行压力测试 推荐.Net memory profiler工具
然后在使用Jprofiler对你的java应用程序进行跟踪
不管是java还是微软的代码 要想高效、及时的回收内存,需要在对象释放的时候显示地切掉与外部的引用,不然可能垃圾要回收好几次才能回收掉
32 楼 flyiclj 2011-06-29  
kingkan 写道

嗯。。。确实如你所说,回归你之前说的线程导致增量问题,的确耐人寻味了,这位同学,有待研究。

我先去请教下大牛,嘿。


可以参考一下之前的回复,这样修改确实可以解决问题,也许原因说的并不完全对,但应该也十分值得参考

cyj86 写道
此问题得到解决
公司技术专家回复如下:
引用

将CWinApp theApp; 放在ping.cpp文件中的最后一行即可。

1. 这不是Java的BUG
2. 这也不是MFC的BUG
3. 这也不能说是程序员造成的BUG
4. 应该是MFC框架结构的特点造成的用法问题(但MSDN上没有说明)。

CWinApp必须定义为全局变量,由C++启动代码运行。
在构造的时候,会初始化MFC中使用的全局数据。
在MFC代码appcore.cpp中可以看到在CWinApp的构造与析构函数中,
对程序使用的一些MFC架构资源进行了分配与释放。

静态链接与动态链接的一个区别是内存的共享,猜测在静态链接时,
CWinApp初始化的内容为全局共享的,在没有进行这个初始化时,
各个线程使用的资源可能会独立申请(没有释放)。


经测试,如此修改后问题不再出现
王总实在V5~
orz

31 楼 kingkan 2011-06-29  
flyiclj 写道
kingkan 写道
flyiclj 写道



试了一下,只new Object内存不会涨,不知道你用的什么版本jdk? 我用的是jdk1.5.0_22
只new对象进程内存动都不带动的,看不出变化


JDK1.6.0.22,持续创建对象情况下,每NEW GC一次,进程内存都会增长。


用JDK1.6.0_23试了一下,未出现内存泄露,进程内存最终会稳定在固定数值

为了加速复现,我去掉了 Thread.sleep(100);,并给JVM增加了参数 -verbose:gc -Xms2m -Xmx4m

加载dll,进程内存最终稳定在22936K
不加载dll,进程内存最终稳定在22012K

不知道你是不是只看了前几次GC就确定有内存泄露了?这个要等稳定了再看吧?


嗯。。。确实如你所说,回归你之前说的线程导致增量问题,的确耐人寻味了,这位同学,有待研究。

我先去请教下大牛,嘿。
30 楼 flyiclj 2011-06-29  
kingkan 写道
flyiclj 写道



试了一下,只new Object内存不会涨,不知道你用的什么版本jdk? 我用的是jdk1.5.0_22
只new对象进程内存动都不带动的,看不出变化


JDK1.6.0.22,持续创建对象情况下,每NEW GC一次,进程内存都会增长。


用JDK1.6.0_23试了一下,未出现内存泄露,进程内存最终会稳定在固定数值

为了加速复现,我去掉了 Thread.sleep(100);,并给JVM增加了参数 -verbose:gc -Xms2m -Xmx4m

加载dll,进程内存最终稳定在22936K
不加载dll,进程内存最终稳定在22012K

不知道你是不是只看了前几次GC就确定有内存泄露了?这个要等稳定了再看吧?
29 楼 kingkan 2011-06-29  
flyiclj 写道



试了一下,只new Object内存不会涨,不知道你用的什么版本jdk? 我用的是jdk1.5.0_22
只new对象进程内存动都不带动的,看不出变化


JDK1.6.0.22,持续创建对象情况下,每NEW GC一次,进程内存都会增长。
28 楼 flyiclj 2011-06-28  
ppgunjack 写道
所以全局变量我觉得解释不通
多线程不会导致共享库的全局变量的拷贝,因为这些线程处于同一虚拟地址空间,都能以相同地址访问动态共享库中的全局变量
如果是多进程访问动态共享库才会出现,每个进程访问共享库会出现拷贝共享库中定义的全局变量的情况


不过修改了之后确实好了,也许还有别的原因吧
27 楼 ppgunjack 2011-06-28  
所以全局变量我觉得解释不通
多线程不会导致共享库的全局变量的拷贝,因为这些线程处于同一虚拟地址空间,都能以相同地址访问动态共享库中的全局变量
如果是多进程访问动态共享库才会出现,每个进程访问共享库会出现拷贝共享库中定义的全局变量的情况
26 楼 flyiclj 2011-06-28  
ppgunjack 写道
cyj86 写道
此问题得到解决
公司技术专家回复如下:
引用

将CWinApp theApp; 放在ping.cpp文件中的最后一行即可。

1. 这不是Java的BUG
2. 这也不是MFC的BUG
3. 这也不能说是程序员造成的BUG
4. 应该是MFC框架结构的特点造成的用法问题(但MSDN上没有说明)。

CWinApp必须定义为全局变量,由C++启动代码运行。
在构造的时候,会初始化MFC中使用的全局数据。
在MFC代码appcore.cpp中可以看到在CWinApp的构造与析构函数中,
对程序使用的一些MFC架构资源进行了分配与释放。

静态链接与动态链接的一个区别是内存的共享,猜测在静态链接时,
CWinApp初始化的内容为全局共享的,在没有进行这个初始化时,
各个线程使用的资源可能会独立申请(没有释放)。


经测试,如此修改后问题不再出现
王总实在V5~
orz

线程看到的链接库资源应该是一份都是同一个地址空间,全局变量出现拷贝的情况是多进程共享


这里没有用到多进程啊,只有多线程
25 楼 flyiclj 2011-06-28  
kingkan 写道
cyj86 写道
kingkan 写道
flyiclj 写道


所谓load的时候就开始泄露是指什么?为什么不新建线程内存就不会增长呢?难道泄露停止了?

可以确认是dll的问题,所以卸载了dll内存泄露自然就终止了

现在要讨论的是 新建线程 和 dll内存泄露 之间有什么联系,要如何修改才能避免这种情况发生?



这位同学,新建线程 和 dll内存泄露 没关系滴。


首先谢谢这位兄弟关注并讨论
确实,按理说新建线程和dll泄漏应该没关系

但现象是只有不断的新建线程 这个dll内存泄漏现象才会体现出来
源码中的连接池正是因为此才可以加速复现问题

不知道你有何方法复现dll泄漏现象 而不新建线程么?



Thread t = new Thread();
t.start();

换成
Object o = new Object();


内存照样泄露,只要加载了这个DLL,你new对象的时候,进程内存都在增长。
我估计是这个DLL做了某些行为导致这样的,至于做了什么行为,在下的C++功力不够看不出来,呵呵



试了一下,只new Object内存不会涨,不知道你用的什么版本jdk? 我用的是jdk1.5.0_22
只new对象进程内存动都不带动的,看不出变化
24 楼 ppgunjack 2011-06-27  
cyj86 写道
此问题得到解决
公司技术专家回复如下:
引用

将CWinApp theApp; 放在ping.cpp文件中的最后一行即可。

1. 这不是Java的BUG
2. 这也不是MFC的BUG
3. 这也不能说是程序员造成的BUG
4. 应该是MFC框架结构的特点造成的用法问题(但MSDN上没有说明)。

CWinApp必须定义为全局变量,由C++启动代码运行。
在构造的时候,会初始化MFC中使用的全局数据。
在MFC代码appcore.cpp中可以看到在CWinApp的构造与析构函数中,
对程序使用的一些MFC架构资源进行了分配与释放。

静态链接与动态链接的一个区别是内存的共享,猜测在静态链接时,
CWinApp初始化的内容为全局共享的,在没有进行这个初始化时,
各个线程使用的资源可能会独立申请(没有释放)。


经测试,如此修改后问题不再出现
王总实在V5~
orz

线程看到的链接库资源应该是一份都是同一个地址空间,全局变量出现拷贝的情况是多进程共享
23 楼 kingkan 2011-06-27  
cyj86 写道
kingkan 写道
flyiclj 写道


所谓load的时候就开始泄露是指什么?为什么不新建线程内存就不会增长呢?难道泄露停止了?

可以确认是dll的问题,所以卸载了dll内存泄露自然就终止了

现在要讨论的是 新建线程 和 dll内存泄露 之间有什么联系,要如何修改才能避免这种情况发生?



这位同学,新建线程 和 dll内存泄露 没关系滴。


首先谢谢这位兄弟关注并讨论
确实,按理说新建线程和dll泄漏应该没关系

但现象是只有不断的新建线程 这个dll内存泄漏现象才会体现出来
源码中的连接池正是因为此才可以加速复现问题

不知道你有何方法复现dll泄漏现象 而不新建线程么?



Thread t = new Thread();
t.start();

换成
Object o = new Object();


内存照样泄露,只要加载了这个DLL,你new对象的时候,进程内存都在增长。
我估计是这个DLL做了某些行为导致这样的,至于做了什么行为,在下的C++功力不够看不出来,呵呵
22 楼 cyj86 2011-06-27  
此问题得到解决
公司技术专家回复如下:
引用

将CWinApp theApp; 放在ping.cpp文件中的最后一行即可。

1. 这不是Java的BUG
2. 这也不是MFC的BUG
3. 这也不能说是程序员造成的BUG
4. 应该是MFC框架结构的特点造成的用法问题(但MSDN上没有说明)。

CWinApp必须定义为全局变量,由C++启动代码运行。
在构造的时候,会初始化MFC中使用的全局数据。
在MFC代码appcore.cpp中可以看到在CWinApp的构造与析构函数中,
对程序使用的一些MFC架构资源进行了分配与释放。

静态链接与动态链接的一个区别是内存的共享,猜测在静态链接时,
CWinApp初始化的内容为全局共享的,在没有进行这个初始化时,
各个线程使用的资源可能会独立申请(没有释放)。


经测试,如此修改后问题不再出现
王总实在V5~
orz
21 楼 cyj86 2011-06-25  
kingkan 写道
flyiclj 写道
kingkan 写道
flyiclj 写道

即使DLL本身有泄露,那也只会在load的时候泄露一次,现在的现象是在java中每建一个线程,内容就会增长,而load只做了一次


呵呵,这位兄台,麻烦你先run一下楼主的这个程序吧。

第一,test1.dll这个DLL在load的时候就开始泄漏,这跟一次两次是没关系,内部泄漏的实现你可以看到,是不断的泄漏。

第二,楼主的java程序并没有造成JVM大内存的消耗,新建的线程很快就被回收,整个过程也只是保持在415个线程左右,堆内存除了新生区new GC比较频繁以外,JVM的内存并没有继续扩容。

第三,该java进程的内存不断的增长,在windows下你可以通过listdlls工具看到,该java进程加载的所有DLL,包括test1.dll也在里面,当你把test1.dll动态卸载时,系统会把进程中test1.dll的内存马上清除,并且java进程也停止增长了喔。


所谓load的时候就开始泄露是指什么?为什么不新建线程内存就不会增长呢?难道泄露停止了?

可以确认是dll的问题,所以卸载了dll内存泄露自然就终止了

现在要讨论的是 新建线程 和 dll内存泄露 之间有什么联系,要如何修改才能避免这种情况发生?



这位同学,新建线程 和 dll内存泄露 没关系滴。


首先谢谢这位兄弟关注并讨论
确实,按理说新建线程和dll泄漏应该没关系

但现象是只有不断的新建线程 这个dll内存泄漏现象才会体现出来
源码中的连接池正是因为此才可以加速复现问题

不知道你有何方法复现dll泄漏现象 而不新建线程么?
20 楼 kingkan 2011-06-24  
flyiclj 写道
kingkan 写道
flyiclj 写道

即使DLL本身有泄露,那也只会在load的时候泄露一次,现在的现象是在java中每建一个线程,内容就会增长,而load只做了一次


呵呵,这位兄台,麻烦你先run一下楼主的这个程序吧。

第一,test1.dll这个DLL在load的时候就开始泄漏,这跟一次两次是没关系,内部泄漏的实现你可以看到,是不断的泄漏。

第二,楼主的java程序并没有造成JVM大内存的消耗,新建的线程很快就被回收,整个过程也只是保持在415个线程左右,堆内存除了新生区new GC比较频繁以外,JVM的内存并没有继续扩容。

第三,该java进程的内存不断的增长,在windows下你可以通过listdlls工具看到,该java进程加载的所有DLL,包括test1.dll也在里面,当你把test1.dll动态卸载时,系统会把进程中test1.dll的内存马上清除,并且java进程也停止增长了喔。


所谓load的时候就开始泄露是指什么?为什么不新建线程内存就不会增长呢?难道泄露停止了?

可以确认是dll的问题,所以卸载了dll内存泄露自然就终止了

现在要讨论的是 新建线程 和 dll内存泄露 之间有什么联系,要如何修改才能避免这种情况发生?



这位同学,新建线程 和 dll内存泄露 没关系滴。
19 楼 flyiclj 2011-06-24  
kingkan 写道
flyiclj 写道

即使DLL本身有泄露,那也只会在load的时候泄露一次,现在的现象是在java中每建一个线程,内容就会增长,而load只做了一次


呵呵,这位兄台,麻烦你先run一下楼主的这个程序吧。

第一,test1.dll这个DLL在load的时候就开始泄漏,这跟一次两次是没关系,内部泄漏的实现你可以看到,是不断的泄漏。

第二,楼主的java程序并没有造成JVM大内存的消耗,新建的线程很快就被回收,整个过程也只是保持在415个线程左右,堆内存除了新生区new GC比较频繁以外,JVM的内存并没有继续扩容。

第三,该java进程的内存不断的增长,在windows下你可以通过listdlls工具看到,该java进程加载的所有DLL,包括test1.dll也在里面,当你把test1.dll动态卸载时,系统会把进程中test1.dll的内存马上清除,并且java进程也停止增长了喔。


所谓load的时候就开始泄露是指什么?为什么不新建线程内存就不会增长呢?难道泄露停止了?

可以确认是dll的问题,所以卸载了dll内存泄露自然就终止了

现在要讨论的是 新建线程 和 dll内存泄露 之间有什么联系,要如何修改才能避免这种情况发生?
18 楼 kingkan 2011-06-23  
flyiclj 写道

即使DLL本身有泄露,那也只会在load的时候泄露一次,现在的现象是在java中每建一个线程,内容就会增长,而load只做了一次


呵呵,这位兄台,麻烦你先run一下楼主的这个程序吧。

第一,test1.dll这个DLL在load的时候就开始泄漏,这跟一次两次是没关系,内部泄漏的实现你可以看到,是不断的泄漏。

第二,楼主的java程序并没有造成JVM大内存的消耗,新建的线程很快就被回收,整个过程也只是保持在415个线程左右,堆内存除了新生区new GC比较频繁以外,JVM的内存并没有继续扩容。

第三,该java进程的内存不断的增长,在windows下你可以通过listdlls工具看到,该java进程加载的所有DLL,包括test1.dll也在里面,当你把test1.dll动态卸载时,系统会把进程中test1.dll的内存马上清除,并且java进程也停止增长了喔。
17 楼 flyiclj 2011-06-23  
kingkan 写道
cyj86 写道
kingkan 写道
flyiclj 写道
kingkan 写道
JVM动态加载的DLL归属于系统进程级别的管理,而DLL的内存资源是自己管理但与进程挂钩。

所以当你的test1.dll的内部内存不断增长而又不释放的话,进程的内存资源会不断增加。但并不影响JVM管理范围内的内存。


这个DLL只加载了一次,而且不做任何调用,即使它的内部内存有泄露,应该也不会影响到JAVA端吧


嗯,不调用是不会影响JVM。但当该进程的使用内存增长到一定程度,JVM或者系统不够内存用的时候,JVM会当掉的。


这是肯定的 系统内存如果都不够了 JVM当然也会出问题
但是和本话题就关系不大了

这里的重点是
dll只加载了一次
而且不做任何调用


DLL本身就有泄漏,System.load进来时,进程内存就开始泄漏了。这个test1.dll就是这种情况啦,除非有些dll非得到执行其内部某些方法才会泄漏,那就不同。关键是DLL内存泄漏点是加载就触发还是调用内部API时触发。


即使DLL本身有泄露,那也只会在load的时候泄露一次,现在的现象是在java中每建一个线程,内容就会增长,而load只做了一次
16 楼 kingkan 2011-06-23  
cyj86 写道
kingkan 写道
flyiclj 写道
kingkan 写道
JVM动态加载的DLL归属于系统进程级别的管理,而DLL的内存资源是自己管理但与进程挂钩。

所以当你的test1.dll的内部内存不断增长而又不释放的话,进程的内存资源会不断增加。但并不影响JVM管理范围内的内存。


这个DLL只加载了一次,而且不做任何调用,即使它的内部内存有泄露,应该也不会影响到JAVA端吧


嗯,不调用是不会影响JVM。但当该进程的使用内存增长到一定程度,JVM或者系统不够内存用的时候,JVM会当掉的。


这是肯定的 系统内存如果都不够了 JVM当然也会出问题
但是和本话题就关系不大了

这里的重点是
dll只加载了一次
而且不做任何调用


DLL本身就有泄漏,System.load进来时,进程内存就开始泄漏了。这个test1.dll就是这种情况啦,除非有些dll非得到执行其内部某些方法才会泄漏,那就不同。关键是DLL内存泄漏点是加载就触发还是调用内部API时触发。
15 楼 cyj86 2011-06-23  
kingkan 写道
flyiclj 写道
kingkan 写道
JVM动态加载的DLL归属于系统进程级别的管理,而DLL的内存资源是自己管理但与进程挂钩。

所以当你的test1.dll的内部内存不断增长而又不释放的话,进程的内存资源会不断增加。但并不影响JVM管理范围内的内存。


这个DLL只加载了一次,而且不做任何调用,即使它的内部内存有泄露,应该也不会影响到JAVA端吧


嗯,不调用是不会影响JVM。但当该进程的使用内存增长到一定程度,JVM或者系统不够内存用的时候,JVM会当掉的。


这是肯定的 系统内存如果都不够了 JVM当然也会出问题
但是和本话题就关系不大了

这里的重点是
dll只加载了一次
而且不做任何调用

相关推荐

    使用JNA替代JNI调用DLL,并解决内存溢出问题

    ### 使用JNA替代JNI调用DLL,并解决内存溢出问题 #### 问题背景 在项目的开发过程中,常常遇到需要处理二进制流数据并对其进行解析处理的情况。这种情况下,如果上层应用平台采用的是Java开发,而底层算法或数据...

    Java_JNI_获得系统进程信息实例.doc

    - **内存管理与资源释放**:虽然示例代码未明确展示,但在实际应用中,开发者应关注内存管理和资源释放,确保快照句柄等资源在使用完毕后被适当释放,避免内存泄漏或资源浪费。 通过以上分析,我们不仅理解了如何...

    Java Native Access JNA-4.5.0

    5. **内存管理**:JNA 提供了内存管理机制,自动处理本地分配和释放内存,避免了内存泄漏问题。 6. **结构体和联合体支持**:JNA 支持Java类映射到C语言的结构体和联合体,使得复杂数据结构的传递变得简单。 7. **...

    javadll.rar_Java编程_Visual_C++_

    7. **Java代码调用**:在Java端,我们声明native方法,并使用`System.loadLibrary()`加载DLL。之后,Java代码就可以像调用普通Java方法一样调用这些native方法。 8. **编译和链接**:使用Visual C++编译C++代码,并...

    释放系统内存独一无二哦

    这类脚本通常包含命令行工具,如"rundll32.exe advapi32.dll, ProcessIdleTasks"或"wmic process call terminate"来结束特定进程,或者使用"powercfg.exe /h off"来禁用休眠文件以节省内存。 总的来说,有效管理...

    SQLite数据库 sqlitedll库文件 sqlite驱动JAR包

    5. **关闭资源**:记得在完成所有操作后关闭连接和其他资源,以避免内存泄漏和资源浪费。 在Windows环境中,`sqlitedll`库文件是用于本地调用SQLite函数的,通常不需要直接在Java程序中处理,除非你打算使用特定的...

    jvm监控工具visualVM

    可以看到本地及远程服务器上的Java进程,并进行连接。你可以选择要监控的应用,获取其JVM配置信息,包括JVM参数、类路径、模块系统等。 3. **性能监视** - **内存监控**:实时显示堆内存、非堆内存、eden区、...

    Jacob实现word转PDF之格式最美转化

    同时,还需要将Jacob的动态链接库(dll文件)放到系统路径下的bin目录,以便Java能够找到并加载它。 2. **初始化COM**:在Java代码中,你需要先进行COM初始化,通常使用` Jacob.AutoReleasePool`来管理COM对象的...

    jni调用c接口完整例子

    - 释放资源非常重要,特别是本地分配的内存,避免内存泄漏。 6. **应用实例**: - 图形处理:JNI可以用于调用图形库,如OpenGL,提升游戏或图像应用的性能。 - 加密解密:使用C/C++实现加密算法,通过JNI调用,...

    sigar包文件.zip

    同时,根据你的操作系统,还需要确保对应的动态链接库文件(如libsigar-x86-linux.so、sigar-amd64-winnt.dll等)被正确加载。这通常涉及到设置系统属性`java.library.path`或者使用JNA的LibraryLoader机制。 总的...

    IDEA工具jprofiler插件(JVM分析利器)

    在IntelliJ IDEA中安装JProfiler插件,开发者可以方便地在IDE内启动或附加到已运行的Java进程进行分析,无需离开开发环境。通过插件,用户可以直接触发JProfiler的各项分析功能,简化了性能调优的工作流程。 **总结...

    SWT 中嵌入Word 控件应用

    8. **资源释放**:使用完Word对象后,务必正确地关闭和释放资源,防止内存泄漏。 9. **SWT布局管理**:为了在SWT界面中合理展示Word控件,需要理解并运用SWT的布局管理器,如`FillLayout`、`GridLayout`等。 通过...

    jacob按目录拆分文档(含dll和jar),代码说明详细

    6. **释放资源**:最后,确保关闭所有打开的Word文档和终止Word进程,避免资源泄漏。 在实际开发中,为了提高效率和可维护性,可以将以上步骤封装成函数或者类,以便重复使用。此外,需要注意的是,由于Jacob依赖于...

    [文档]深入理解Andorid重难点.ppt

    Keywords.h通常包含一些预定义的宏,而DllMain函数在Windows DLL加载时会被调用,但在Android中,可能指的是初始化时的一些特定操作。 **Android常用类分析** - **RefBase、sp和wp**:RefBase是Android中用于引用...

Global site tag (gtag.js) - Google Analytics