I'm afraid you're wrong: when With - End With is used compiler has to evaluate property and "decide" to which object it (property) belongs to ... as you may have nested With (sample below) so having Object.Property will actually speed it up but code itself becomes a bit redundant.
Well here are the results I got. I went with szlamany's suggestion of a listview subitem thing (and because it is very early morning I probably coded it all wrong )
Code:
Results averaged over 4 runs each at
normal thread priority
With Block Dot Reference
IDE 129 ms 578 ms
EXE 106 ms 613 ms
And the test code was:
Code:
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
'
Private Sub Form_Load()
ListView1.ListItems.Add 1, "Thing", "Thing"
ListView1.ListItems.Item(1).SubItems(1) = "blah"
End Sub
Private Sub Command1_Click()
Dim lngStartTime As Long
Dim lngTotalTime As Long
Dim lngTimeAvg As Long
Dim lngCount As Long
Dim lngLoopCount As Long
LoopDotRefStart:
lngCount = 0
lngStartTime = GetTickCount()
Do
ListView1.ListItems(1).SubItems(1) = lngCount
lngCount = lngCount + 1
Loop Until lngCount = 100000
lngTotalTime = lngTotalTime + (GetTickCount() - lngStartTime)
lngLoopCount = lngLoopCount + 1
If (lngLoopCount < 5) Then GoTo LoopDotRefStart
lngTimeAvg = lngTotalTime / 4
Text1.Text = "Dot reference (4x): " & lngTimeAvg & "ms"
lngTotalTime = 0
lngLoopCount = 0
With ListView1.ListItems(1)
LoopWithBlockStart:
lngCount = 0
lngStartTime = GetTickCount()
Do
.SubItems(1) = lngCount
lngCount = lngCount + 1
Loop Until lngCount = 100000
lngTotalTime = lngTotalTime + (GetTickCount() - lngStartTime)
lngLoopCount = lngLoopCount + 1
If (lngLoopCount < 5) Then GoTo LoopWithBlockStart
End With
lngTimeAvg = lngTotalTime / 4
Text1.Text = Text1.Text & vbCrLf & "With block (4x): " & lngTimeAvg & "ms"
End Sub
Great thread I also remember reading that the dots reduce performance.
Nice performance testing guys. This makes me wonder how OOP relates to performance since its all
object dot object dot blah, blah, blah..., but since its object oriented that probably makes the difference.
VB/Office Guru™ (AKA: Gangsta Yoda™ ®)
I dont answer coding questions via PM. Please post a thread in the appropriate forum.
Don't have time to play with myselft BUT
you might also want to try running your example using an object variable in lieu of the object itself. I think "With" will still be faster.
For example:
Instead of:
Code:
ListView1.ListItems.Item(1).SubItems(1) = "blah"
Use:
Code:
Dim objLV as ListView
objLV.ListItems.Item(1).SubItems(1) = "blah"
Made it back. Just read your comment. Had to LOL at myself as didn't get double meaning at first read.
--------------------------
RobDog888
Setting object variable OR object = Nothing serves NO purpose. If I can track down article will post here. When Sub/Function exits, stack is cleared and all variable objects are also automatically cleared. Use to do (= Nothing) but stopped, and SO far no issues.
David,
you may want to reconsider your habits (or technics if you will). Stack isn't alwys gets cleared up especially when procedure has Static vars declared so explicitly resetting all object vars is really somthing you want to do without exceptions.
Setting object variable OR object = Nothing serves NO purpose. If I can track down article will post here. When Sub/Function exits, stack is cleared and all variable objects are also automatically cleared. Use to do (= Nothing) but stopped, and SO far no issues.
Wow! This is a very dangerous statement, even if it's basically true. VB will clear the stack memory when a procedure ends however assuming that the statement is always true will cause problems. If you for example use ADO and open a connection or recordset object and just leave it open when the procedure ends you can not for sure say that the RDBMS will close the connection properly and you might end up with corrupted data.
Also if you would port part of your code to a classic ASP page and still use the same approach, IIS will not clear the memory used by an object until the session ends. So you should always set your object references to Nothing when you don't need them anymore.
David, it is just good programming practice to explictly destroy your objects because, like just posted, there are
instances where the object will not get destroyed, even sometimes after your program is terminated. When doing
Office automation, especialy, you ALWAYS need to destroy objects explictly.
When programming with COM object you always run the risk of leaving objects in memory if they are not destroyed.
VB/Office Guru™ (AKA: Gangsta Yoda™ ®)
I dont answer coding questions via PM. Please post a thread in the appropriate forum.
I need to change my statement above.... IIS will never remove your object from memory unless you do it yourself. It will stay there forever, or until the web services has been stoped and restarted... unless you destroy the object yourself by setting it to Nothing.
There a few possible reasons why JR's code gets different results from mine:
I used a variable within an object within a ListView object, JR used a variable within a Type
I put my code in a form, JR's in a module
My With block was excluded from the loop, JR's was included
The last point has actually a fairly significant impact on performance. If you place the With and End With statements outside the loop, the performance is dramatically increased compared to when they are placed inside the loop.
So I tested it with JR's code, and these are the results I got:
Code:
High thread priority
Including Excluding Dot
statements statements reference
IDE 1,783,981 2,043,114 2,036,235
EXE 3,590,492 4,081,684 3,974,999
You can see both in the IDE and compiled to native code (with full optimisations - JR what were you doing compiling to Pcode ) - Using With (and leaving the With/End With statements outside the loop) is slightly faster. Including the statements in the loop makes it definitely slower than not using a With block, because I suppose the the memory address is being resolved every time. If the contents of the loop were a lot longer then the results would probably be different.
So Mr Roman, it would seem your code supports my results just as conclusively as my own
Last edited by penagate; Apr 25th, 2005 at 12:19 AM.
szlamany makes a good point that maybe the book was referring to multi dot objects.
Hey szlamany, if you can find that reference about the dots please post it.
VB/Office Guru™ (AKA: Gangsta Yoda™ ®)
I dont answer coding questions via PM. Please post a thread in the appropriate forum.
szlamany makes a good point that maybe the book was referring to multi dot objects.
Hey szlamany, if you can find that reference about the dots please post it.
It's not very conclusive - but here it is...
From page 774-776 of the MS Visual Basic 6.0 Programmer Guide - chapter 15 "Designing for Performance and Compatibility":
When referencing other applications' objects from Visual Basic, you use the dot syntax "." to navigate an objects hierarchy of collections, objects, properties, and methods. It is not uncommon to create very lengthy navigation strings. For example:
' Refers to cell A1 on Sheet1 in the first workbook
' of an Microsoft Excel spreadsheet.
Application.Workbooks.Item(1).Worksheets.Item_
("Sheet1").Cells.Item(1,1)
In addition to being a rather lengthy string to type, this line of code is fairly difficult to read — and it is extremely inefficient.
When calling an object from Visual Basic, each "dot" requires Visual Basic to make multiple calls.
To write the most efficient applications, minimize the use of dots when referencing an object.
You can usually minimize the dots by analyzing the objects and methods available to you. For example, the above line of code can be shortened by removing the Item method (this is the default method for collections anyway, so youll rarely use it in code) and by using the more efficient Range method:
' Refers to cell A1 on Sheet1 in the first workbook
' of an Microsoft Excel spreadsheet.
Application.Workbooks(1).Worksheets("Sheet1")_
.Range("A1")
You can shorten this even further by rewriting the code so that it refers to the active sheet in the active workbook, instead of a specific sheet in a specific workbook:
' Refers to cell A1 on the active sheet in the
' active workbook.
Range("A1")
Of course, the above example assumes its OK to refer to cell A1 of any sheet that happens to be active.
Use Set and With...End With
Using the Set statement also allows you to shorten navigation strings and gives you a bit more control over your code. The following example uses the Dim and Set statements to create variables that refer to frequently used objects:
Dim xlRange As Object
Set xlRange = Application.ActiveSheet.Cells(1,1)
xlRange.Font.Bold = True
xlRange.Width = 40
Visual Basic provides the With...End With construct to set an implied object within code:
With Application.ActiveSheet.Cells(1,1)
.Font.Bold = True
.Width = 40
End With
I also found the same info on MSDN site - here's the link (where I did the copy/paste from!):
It mentions mostly that a "dot" represents a series of calls to resolve the object at that dot. That makes sense.
I think what I can take away from this is that not all objects will behave the same way - some might be simply memory locations that need to be resolved - some might be more complex (EXCEL OLE - stuff like that).
I think that using WITH (or SET as RobDog mention) for both readability and possible better performance is a good idea - a good habit to get into.
*** Read the sticky in the DB forum about how to get your question answered quickly!! ***
Please remember to rate posts! Rate any post you find helpful - even in old threads! Use the link to the left - "Rate this Post".
Tried above link and had problems, link has now been corrected. I should also clarify my point to mean "the blanket use of Nothing" rather than using it selectively -- see discussion in link.
Last edited by dw85745; Apr 25th, 2005 at 10:32 AM.
DW - that was a really good read - thanks for the info.
I particularly liked the info on circular references - probably the major reason for what people like to call memory leaks, which are really redundant uses of memory from poor event coding logic in the first place (really memory abuse!).
*** Read the sticky in the DB forum about how to get your question answered quickly!! ***
Please remember to rate posts! Rate any post you find helpful - even in old threads! Use the link to the left - "Rate this Post".
My point was that habits are hard to kill. Just because VB kills the reference and therefor decrease the reference count in the object doesn't mean all environments does. One of the main problems with running classic ASP on IIS is that the number of objects created are always increased and never destroyed unless you would restart the web services. This would be easily avoided if developers would remember to set their references to nothing but alas VB has tought us that this is not necassary so people never get into this habit.
Yes, it was a good read but I dont 100% agree with him for a few reasons.
First, his experience is archaic. Windows 95 was his latest working enviroment. What, no experience
with 98/2000/XP. Come on get into the 21st century.
He doent have any experience with VB6? Things changed allot from VB3, 4, and 5. I mean come on,
upgrade so you can get with the same program as the majority of the users.
Second, he does not cover other scenerios other then the basic Standard Exe apps and does not discuss anything
complex. We are not writting "Hello World" programs, are we?
Third, he does not include COM and barely mentions ActiveX.
Yes, the guy know some stuff, but I mean come on. He may have been in the industry back in the day, but he's a
social worker or something like that now!
VB/Office Guru™ (AKA: Gangsta Yoda™ ®)
I dont answer coding questions via PM. Please post a thread in the appropriate forum.
He doent have any experience with VB6? Things changed allot from VB3, 4, and 5. I mean come on,
upgrade so you can get with the same program as the majority of the users.
From that page I thought so as well, but in the foreword he mentions:
Since then I've been working with Microsoft on every cut of Visual Basic, up to and including VB.Net (in Beta 2 at the time of writing).
Though again, it's by a different writer whom the main one asked to write the introduction. I suppose it was written before the rest of the book, so by the time it was published, .Net was probably already out...
True, but either way I feel its a bit outdated and needs a definate update. VS.NET beta 2 was still years
ago and its a horse of a different color. VS has a GarbageCollector object that cleans up objects so if you
miss destroying some you can call the collection and poof, your clean. Nothing like VB6!
VB/Office Guru™ (AKA: Gangsta Yoda™ ®)
I dont answer coding questions via PM. Please post a thread in the appropriate forum.
I couldn't help but contribute as this thread is now referenced from another thread that I followed to here . . .
set obj=nothing
. . .does not release the reference to an object. It calls the Release function on the IUnknown interface to which is bound. If you recall IDispatch is a superset of IUnknown. It also marks the local object as 'Nothing' for VB's type checking.
If the object is NOT nothing and the object is local to a function then VB will automatically decrement using the IUnknown.Release function as part of the End Function memory management (it will release memory used by other data-types, too)
When the object itself reaches a usage count of zero, the object itself destroys itself. There are no mechanisms (apart from zero'ing the objects memory) where VB can control lifetime of an object apart from incrementing or decrementing using the IUnknown interface using AddRef,and Release, respectively.
With Block
The with block creates a temporary object which points to the relevant IUnknowninterface of which you declare just after the With. So With MyObj.Child.Leaf will create a temporary object of type Leaf and will operate directly on the temporary object. This is safe to do as VB uses a reference scheme and no absolute memory copying. You can mimic the performance effect by doing the same - declare an object of type Leaf, and perform actions directly upon it will effect the parent MyObj's Leaf object too. You can verify this my checking the ObjPtr return value of MyObj.Child.Leaf, and the temp Leaf object. Be careful to grab the default interface, and not the IUnknown one as ObjPtr returns the reference to the interface and NOT to the object itself (so objects with multiple interfaces will need to be discerned using TypeOf)
Hope this adds a little . . .
"As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein