1234

ExcelHome技术论坛

用户名  找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

帖子
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
12
返回列表 发新帖
楼主: duowjgwsm

[求助] 一个对象会多次分配内存吗?

[复制链接]

TA的精华主题

TA的得分主题

发表于 2014-7-18 10:03 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖已被收录到知识树中,索引项:数据类型和基本语句
liucqa 发表于 2014-7-18 08:46
如果用WB控件的话,会有内存泄漏问题,这不一定是控件的bug。

如果采用动态创建WB的方法,据说可以手工 ...

我已经查到上次造成内存泄漏的源码了,是在循环中使用
With CreateObject("xxxxx")


end with

最后对象的实体内存没有得到释放造成了泄露。 With End With 之间引用对象,可以认为是匿名引用对象吧。微软没有公开细节,但是从Set 语句的表现来看,是立即将失去引用的对象内存释放了。是否可以认为这是Set 语句本身带的操作内存的功能而不是VB 整体的内存管理策略?

TA的精华主题

TA的得分主题

发表于 2014-7-18 10:23 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
hehex 发表于 2014-7-18 10:03
我已经查到上次造成内存泄漏的源码了,是在循环中使用
With CreateObject("xxxxx")

你再仔细测测

TA的精华主题

TA的得分主题

发表于 2014-7-18 11:35 | 显示全部楼层
hehex 发表于 2014-7-17 13:54
这个问题很有趣。

aa 是一个局部变量,里面装的是对象实体的引用。在你执行set aa = createobject("..." ...

循环制作一定数量的对象,比如说5000个过或一万个,检查一下内存,试试。

TA的精华主题

TA的得分主题

发表于 2014-7-18 11:57 | 显示全部楼层
liucqa 发表于 2014-7-18 10:23
你再仔细测测

下面这段代码,要提取两千多页的网页数据,在循环内使用with createobject("xxx") 造成内存泄漏,经查每页抓取对象实体占3M 内存,当系统内存占用达到1.5G 时excel 崩溃。如前面测试,如果使用Set 语句则程序不会出现问题。
  1. Sub 提取_XMLHTTPP()

  2.     Dim URL$, hmlFile, arr(), r, s, i%, j%

  3.     Dim t As Single

  4.     Dim brr(), crr()

  5.     Application.ScreenUpdating = False

  6.     Application.DisplayAlerts = False

  7.     Application.ShowWindowsInTaskbar = False

  8.     On Error Resume Next

  9.    
  10.    
  11.     t = Timer

  12.     brr = Sheets(1).Range("a1").CurrentRegion.Value

  13.    
  14.     For k = 1089 To UBound(brr)


  15.     Workbooks.Add

  16.    
  17.     URL = "http://www.marketwatch.com/investing/Stock/" & brr(k, 1) & "/financials/income/quarter"

  18.    
  19.     With CreateObject("microsoft.xmlhttp")

  20.         .Open "GET", URL, False

  21.         .send

  22.         Do Until .ReadyState = 4

  23.             DoEvents

  24.         Loop

  25.         Set hmlFile = CreateObject("htmlfile")

  26.         hmlFile.body.innerhtml = .responsetext

  27.     End With

  28.    
  29.     Set r = hmlFile.all.tags("table")(0).Rows

  30.     ReDim arr(r.Length - 1, r(0).Cells.Length - 1)

  31.     For i = 0 To UBound(arr)

  32.         For j = 0 To UBound(arr, 2)

  33.             arr(i, j) = r(i).Cells(j).innertext

  34.         Next

  35.     Next

  36.    
  37.       Set s = hmlFile.all.tags("table")(1).Rows

  38.     ReDim crr(s.Length - 1, s(0).Cells.Length - 1)

  39.     For l = 0 To UBound(crr)

  40.         For m = 0 To UBound(crr, 2)

  41.             crr(l, m) = s(l).Cells(m).innertext

  42.         Next

  43.     Next

  44.     Set hmlFile = Nothing

  45.     Set r = Nothing

  46.     Set s = Nothing

  47.    
  48.     Cells.ClearContents

  49.     Range("a1").Resize(UBound(arr) + 1, UBound(arr, 2) + 1) = arr

  50.     Range("a" & i + 1).Resize(UBound(crr) + 1, UBound(crr, 2) + 1) = crr

  51.     Cells.Columns.AutoFit

  52.     ActiveWorkbook.SaveAs "D:" & brr(k, 1) & ".xlsx"

  53.     ActiveWorkbook.Close

  54.    
  55.    
  56.     Next

  57.     Application.ScreenUpdating = True

  58.     Application.DisplayAlerts = True

  59.     Application.ShowWindowsInTaskbar = True

  60.     MsgBox Timer - t

  61.    
  62. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2014-7-18 13:30 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 liucqa 于 2014-7-18 13:42 编辑

Set hmlFile = CreateObject("htmlfile")
hmlFile.body.innerhtml = .responsetext

问题出在这里吧,你把对象的一个属性引用给了另一个对象的属性,前者就不能自动释放了,而临时变量是不能手工释放的,这就造成了典型的内存泄漏

你可以试试改成字符串拷贝语句,把原来的浅复制变成深复制,摆脱对原对象属性的直接引用,看看是不是解决问题。

不过,最好的办法,还是不要在With里面跨End With使用对象或者其属性的引用。或者把代码改成不使用With语句,这样就能人工释放对象了。



其实,如果你学习其他的语言,都会涉及到对象的浅复制和深复制问题。字符串表面上是个值变量,实际上是个特殊的引用变量。因此,使用上要小心

数组有的时候,如果使用不当,也会发生类似的泄漏问题。

实际上,在写代码的时候,如非万不得已,尽量不要在编程中使用自动生成的临时变量,这是个基本规则,能避免很多麻烦。

TA的精华主题

TA的得分主题

发表于 2014-7-18 16:10 | 显示全部楼层
liucqa 发表于 2014-7-18 13:30
Set hmlFile = CreateObject("htmlfile")
hmlFile.body.innerhtml = .responsetext

感谢学导老师,通过这个帖子又学到了不少知识。
不过上面那个程序不是我写的,是别人出了问题找我改的。

数组的泄漏问题,俺已经感觉到了,是指动态数组的问题吧。

字符串是引用变量,这个俺也知道一些,经你这么一提,印象会更加深刻一些。

最大的收获是通过本帖深刻了解了VB 的内存回收模式,是使用.Com 的计数内存回收模式。使用计数内存回收
虽然很多时候被人诟病,认为不如.net 的整体gc 模式,但是仍然也算是一种内存回收机制吧。

关于上面的程序的具体泄露点,俺准备回家之后再详细测试一下,那个直接对另一个变量的属性的赋值语句断开
赋到变量中去,然后看看是否能正确回收内存。还是实验一下,更好。

TA的精华主题

TA的得分主题

发表于 2014-7-18 16:19 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
hehex 发表于 2014-7-18 16:10
感谢学导老师,通过这个帖子又学到了不少知识。
不过上面那个程序不是我写的,是别人出了问题找我改的。 ...

那代码错误太多,你可以作为反面教材进行分析

实际上,在循环体内部使用CreateObject是非常不好的做法的,而用With语句就更加错误了

VB的内存管理已经很方便了,但实际操作的时候,如果不按照规矩写代码,那什么事情都会发生的

我也希望其他会员能从这个帖子中学到一点写程序的基本规则...

TA的精华主题

TA的得分主题

发表于 2014-7-18 16:39 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
学习        
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

1234

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2025-3-1 11:22 , Processed in 0.021824 second(s), 6 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表