Code Comments
Programming Forum and web based access to our favorite programming groups.I "refresh" the thread http://communities2.microsoft.com/c...b7-77f42b00681a because many solutions have been proposed and I wanted to verify and give results to the ng. I verified objects collection vs objects array (no doubt about the fact that UDTs array would be the fastest). That's what appened working with 100000 instances: OBJECTS COLLECTION -------- Dim coll As New Collection For i = 0 To 100000 coll.Add New myObject, CStr(i) Next i Allocation: 8 seconds For i = 0 To 100000 coll.Remove CStr(i) Next i Release: 35 seconds For i = 0 To 100000 coll.Remove 1 Next i Release: 33 seconds For i = 100000 To 0 Step -1 coll.Remove i Next i Killed after 2 minutes, only about 10000 objects released For i = 100000 To 0 Step -1 coll.Remove CStr(i) Next i Release: 34 seconds Set coll = Nothing Release: 32 seconds OBJECTS ARRAY ------- Dim arr(100000) As myObject For i = 0 To UBound(arr, 1) Set arr(i) = New myObject Next i Allocation: 2 seconds For i = 0 To UBound(arr, 1) Set arr(i) = Nothing Next i Release: 17 seconds For i = UBound(arr, 1) To 0 Step -1 Set arr(i) = Nothing Next i Release: 17 seconds I also tried a dynamic array released by Redim arr(0); same elapsed as above : Allocation: 2 seconds Release: 17 seconds COMMENTS: a) Arrays are very faster than Collections b) Rank 1 - Set coll = Nothing 2 - Removing 1st ordinal item 3 - Removing in reversed key order 4 - Removing in key order 5 - Removing in reversed ordinal order (geologic time) c) Release time in collection test seems to be spent 1/2 navigating thru the collection, 1/2 releasing memory. Total time about 34 seconds, only 17 seconds the memory release time, as derived from array test (where non navigation occurs). d) It seems that nothing can speed up memory release of instances (arrays perform better because there is no collection structure to navigate thru, bu t memory release time remains the same). So one question remains I can't imagine the answer: What does system do to release the process memory instantly when I kill the process? Many many many thanks for an answer. PS About Scripting.Dictionary: I hope I will try soon About SQL Server: My in-memory DB is loaded from a disk database (MS Access). I choose an in-memory structure to process data because of speed needs Tank you nevertheless.
Post Follow-up to this messageYour last question is easy: It deletes the process and it's virtual address space. If you kill the process with TerminateProcess then their is no object-level cleanup, only very basic cleanup to release certain resources back to the O/S. The process heap(s) are process-specific. Memory is only returned to the heap when it is explicitly deallocated, and may then be used to service subsequent allocation requests within that process. When the process is terminated, *all* the virtual address space is torn down: any physical memory and paging file resources are returned to the O/S. It doesn't waste time messing with stuff inside the heap because it was merely a process entity. However, if the process were terminated with a WM_CLOSE message then the situation may be different. The application is then taking responsibility for tearing down its own objects, and so the heap will be accessed. Many systems allow memory to be allocated from separate heaps (sometimes called zones). This has a number of advantages: In a multi-threaded environment, each thread has items allocated from its own heap, thus reducing thread contention (see the 'Hoard' memory allocator for instance). Also, memory can be reclaimed in one operation by simply deleting the heap, rather than returning every single memory packet back to a single heap. Tony Proctor "nisant" <nisant@discussions.microsoft.com> wrote in message news:4BD578E1-9C58-421E-AA4F-BA7AEF6B1B84@microsoft.com... > I "refresh" the thread > http://communities2.microsoft.com/c...b7-77f42b00681a > > because many solutions have been proposed and I wanted to verify and give > results to the ng. > > I verified objects collection vs objects array (no doubt about the fact that > UDTs array would be the fastest). > > That's what appened working with 100000 instances: > > OBJECTS COLLECTION > -------- > Dim coll As New Collection > > For i = 0 To 100000 > coll.Add New myObject, CStr(i) > Next i > Allocation: 8 seconds > > > For i = 0 To 100000 > coll.Remove CStr(i) > Next i > Release: 35 seconds > > > For i = 0 To 100000 > coll.Remove 1 > Next i > Release: 33 seconds > > > For i = 100000 To 0 Step -1 > coll.Remove i > Next i > Killed after 2 minutes, only about 10000 objects released > > For i = 100000 To 0 Step -1 > coll.Remove CStr(i) > Next i > Release: 34 seconds > > Set coll = Nothing > Release: 32 seconds > > > OBJECTS ARRAY > ------- > Dim arr(100000) As myObject > > For i = 0 To UBound(arr, 1) > Set arr(i) = New myObject > Next i > Allocation: 2 seconds > > For i = 0 To UBound(arr, 1) > Set arr(i) = Nothing > Next i > Release: 17 seconds > > For i = UBound(arr, 1) To 0 Step -1 > Set arr(i) = Nothing > Next i > Release: 17 seconds > > I also tried a dynamic array released by Redim arr(0); same elapsed as above: > Allocation: 2 seconds > Release: 17 seconds > > COMMENTS: > > a) Arrays are very faster than Collections > > b) Rank > 1 - Set coll = Nothing > 2 - Removing 1st ordinal item > 3 - Removing in reversed key order > 4 - Removing in key order > 5 - Removing in reversed ordinal order (geologic time) > > c) Release time in collection test seems to be spent 1/2 navigating thru the > collection, 1/2 releasing memory. Total time about 34 seconds, only 17 > seconds the memory release time, as derived from array test (where non > navigation occurs). > > d) It seems that nothing can speed up memory release of instances (arrays > perform better because there is no collection structure to navigate thru, but > memory release time remains the same). > > So one question remains I can't imagine the answer: > > What does system do to release the process memory instantly when I kill the > process? > > Many many many thanks for an answer. > > PS > About Scripting.Dictionary: > I hope I will try soon > > About SQL Server: > My in-memory DB is loaded from a disk database (MS Access). > I choose an in-memory structure to process data because of speed needs > > Tank you nevertheless.
Post Follow-up to this message"Tony Proctor" wrote: >...... > Also, memory can be reclaimed in one operation by simply deleting the heap , > rather than returning every single memory packet back to a single heap. > Very interesting. I tried on the fly to use these informations in my test, via API, getting process heap handle (GetProcessHeap) before in-memory DB loading and trying to free the mamory destroying the heap before program termination. Running this in IDE, VB crashed. I suppose I destroyed the IDE heap as well. Running in a generated .exe program I observed the usual slow memory release . Trivial approach to the problem, I know. But do you think it's possible, in a VB program, to force a fast release using memory API? In other words allocate a large chunks of address space, use it to store my collection of objects, then instantly free memory and reallocate it if necessary for another collection allocation ?
Post Follow-up to this messageHi, nisant schrieb: > > "Tony Proctor" wrote: > > > Very interesting. > > I tried on the fly to use these informations in my test, via API, getting > process heap handle (GetProcessHeap) before in-memory DB loading and tryin g > to free the mamory destroying the heap before program termination. > > Running this in IDE, VB crashed. No wonder. > I suppose I destroyed the IDE heap as well. > > Running in a generated .exe program I observed the usual slow memory relea se. > > Trivial approach to the problem, I know. > > But do you think it's possible, in a VB program, to force a fast release > using memory API? > In other words allocate a large chunks of address space, use it to store m y > collection of objects, then instantly free memory and reallocate it if > necessary for another collection allocation ? No, you can't. It is VB which decides where to store the objects. But you can decide, where the object *pointers* go, but this would not help either. One thing should be possible, but its awful: Set all individual object references to zero using RtlFillMemory. If in a collection, set the collections pointer to zero. But as said, this is awful, nearly as awful as killing the process. And it should be done only when you are finished with your app. Don't use it to create and destroy objects intermediately. Better don't use it at all :-) If you want to have objects in a memory space where you have your hands on, use Curlands lightweight objects. Or better (as easier), use UDTs. Create one UDT and one wrapper class per DB table. Put all the table's records in an array of UDTs. The wrapper class then gives transparent access to the records. If done right, there should be no difference in accessing the records when using one class instance per record (as you probably do now) or a wrapper class for all records, besides some index value in the accessing methods. Even this can be omitted if you set the index, using a separate property, before accessing a records data. And the wrapper objects can be held in a collection, if you want to. Sorry, but your current design (using hundreds of thousands of classic VB class instances) is not suitable for VB. You should change it. -- Ulrich Korndoerfer VB tips, helpers, solutions -> http://www.proSource.de/Downloads/
Post Follow-up to this messageThank you, Ulrich, for your "inexorable" analysis. Now I know what I can do using VB and what I can't dealing with objects instances. "Ulrich Korndoerfer" wrote: > Hi, > > nisant schrieb: > > No wonder. > > > No, you can't. It is VB which decides where to store the objects. > > But you can decide, where the object *pointers* go, but this would not > help either. > > One thing should be possible, but its awful: > > Set all individual object references to zero using RtlFillMemory. If in > a collection, set the collections pointer to zero. But as said, this is > awful, nearly as awful as killing the process. And it should be done > only when you are finished with your app. Don't use it to create and > destroy objects intermediately. Better don't use it at all :-) > > If you want to have objects in a memory space where you have your hands > on, use Curlands lightweight objects. > > Or better (as easier), use UDTs. Create one UDT and one wrapper class > per DB table. Put all the table's records in an array of UDTs. The > wrapper class then gives transparent access to the records. If done > right, there should be no difference in accessing the records when using > one class instance per record (as you probably do now) or a wrapper > class for all records, besides some index value in the accessing > methods. Even this can be omitted if you set the index, using a separate > property, before accessing a records data. And the wrapper objects can > be held in a collection, if you want to. > > Sorry, but your current design (using hundreds of thousands of classic > VB class instances) is not suitable for VB. You should change it. > > -- > Ulrich Korndoerfer > > VB tips, helpers, solutions -> http://www.proSource.de/Downloads/ > >
Post Follow-up to this message"Ulrich Korndoerfer" <ulrich_wants_nospam@prosource.de> wrote > Or better (as easier), use UDTs. Create one UDT and one wrapper class > per DB table. Put all the table's records in an array of UDTs. The > wrapper class then gives transparent access to the records. Does everyone else recognise that as the flyweight pattern? I was just thinking that giving it a name, might make it easier to talk abou t, later on..... LFS
Post Follow-up to this messageHi, Larry Serflaten wrote: > > "Ulrich Korndoerfer" <ulrich_wants_nospam@prosource.de> wrote > > > Does everyone else recognise that as the flyweight pattern? How did it come that you did think to recognise it? To your info, it is not. Actually, the info given from my statement above is very little. But not little enough to see, that it can not be the flyweight pattern ;-) I gave just a hint how one could proceed. Of course the base of this hint is: minimize the number of objects. Instead creating one object for each table record (an object which carries the record data as internal state), try to use fewer objects (fewer than record count). One method could be (and this it what I intended with my hint without going to deep at this point, as I don't know if the OP is interested in): Make one object, which contains *all* records in its internal state. This could be a self made collection, which eg could hand out data using the records primary key as the collection key. And does contain some handy methods (like loading a record from the DB, allow changes to the record, storing changed record back to the DB, do a selection based on some filter criteria and so on). This should already be mighty enough. Now it depends on the OP needs (which I don't know) if he should go further. If he needs concurrent access from several clients to the records, then the flyweight pattern could have benefits. But the flyweight pattern is more complicated to implement, so in the first step I did not suggest it. The flyweight pattern needs the implementation of a class factory producing the flyweights and of course the flyweight too. The flyweight idea is to hold the data (the records) in external state (outside of any object) and to create and hand out (on demand on the factory) a flyweight instance bound (by a data pointer) to a currently to be processed individual record. The flyweight would implement pretty much the same functionality as my one for all object from above (except of filtering, as a flyweight is responsible for only one of the records): load record from database, allow changes to the records (via flyweight properties), store back to DB and so on. If a concurrent user wants access to the same record, the class factory does not create a new instance but hands out the already created one. So the amout of objects is reduced too (but there would be eventually more than one being around at the same time). But it seems to me that flyweights are not so good on typical database tasks. -- Ulrich Korndoerfer VB tips, helpers, solutions -> http://www.proSource.de/Downloads/
Post Follow-up to this messageIf the UDT contains variable-length String fields then you have a similar memory deallocation performance hit when the array is deleted Tony Proctor "Ulrich Korndoerfer" <ulrich_wants_nospam@prosource.de> wrote in message news:415A964B.5856DC9B@prosource.de... > Hi, > > Larry Serflaten wrote: > > How did it come that you did think to recognise it? To your info, it is > not. Actually, the info given from my statement above is very little. > But not little enough to see, that it can not be the flyweight pattern > ;-) > > I gave just a hint how one could proceed. Of course the base of this > hint is: minimize the number of objects. > Instead creating one object for each table record (an object which > carries the record data as internal state), try to use fewer objects > (fewer than record count). > > One method could be (and this it what I intended with my hint without > going to deep at this point, as I don't know if the OP is interested > in): > > Make one object, which contains *all* records in its internal state. > This could be a self made collection, which eg could hand out data using > the records primary key as the collection key. And does contain some > handy methods (like loading a record from the DB, allow changes to the > record, storing changed record back to the DB, do a selection based on > some filter criteria and so on). > > This should already be mighty enough. Now it depends on the OP needs > (which I don't know) if he should go further. If he needs concurrent > access from several clients to the records, then the flyweight pattern > could have benefits. But the flyweight pattern is more complicated to > implement, so in the first step I did not suggest it. The flyweight > pattern needs the implementation of a class factory producing the > flyweights and of course the flyweight too. > > The flyweight idea is to hold the data (the records) in external state > (outside of any object) and to create and hand out (on demand on the > factory) a flyweight instance bound (by a data pointer) to a currently > to be processed individual record. The flyweight would implement pretty > much the same functionality as my one for all object from above (except > of filtering, as a flyweight is responsible for only one of the > records): load record from database, allow changes to the records (via > flyweight properties), store back to DB and so on. If a concurrent user > wants access to the same record, the class factory does not create a new > instance but hands out the already created one. > > So the amout of objects is reduced too (but there would be eventually > more than one being around at the same time). But it seems to me that > flyweights are not so good on typical database tasks. > > > > > -- > Ulrich Korndoerfer > > VB tips, helpers, solutions -> http://www.proSource.de/Downloads/ >
Post Follow-up to this message"Ulrich Korndoerfer" <ulrich_wants_nospam@prosource.de> wrote > > How did it come that you did think to recognise it? You described a situation that had external data (the array of UDTs) and one object that gives access to the records. That lead me to think that object would contain properties to view and modify one record at a time, (much like a cursor). There are sub-classes of the flyweight pattern that are not shared, or do not use a factory. While the typical flyweight pattern may be thought of as passing out many copies of external data, and using a factory to get a new reference, I have always associated this sort of access to be under the definition of the flyweight pattern too. The object would maintain no state of its own, and would only return data from the UDTs or perform calculations on that data, and return the result. If not the flyweight pattern, then what? LFS
Post Follow-up to this messageHi, Tony Proctor wrote: > > If the UDT contains variable-length String fields then you have a similar > memory deallocation performance hit when the array is deleted > > Tony Proctor The deallocation costs are not similar. See this little test: Times in ms on my system for destroying an array of simplest (no code in them, just plain empty class) objects by erasing the array, and times needed for destroying an array holding strings of varying content and length of about 100 chars, which are 200 bytes at least, and such consuming more memory than the objects (which consume about 100 bytes per instance), are: Element count N Object array String array 1000 6 1 2000 13 2 4000 33 6 8000 ~110 12 16000 ~750 25 32000 ~3300 50 64000 ~13200 103 Creation methods were: For i = 1 To N s(i) = CStr(i) & String$(100, "*") Next i For i = 1 To N Set c(i) = New Class1 Next i and deallocation methods were: Erase s Erase c Deallocation time for strings is linear to N, deallocation of objects (despite the fact that in this test case they consume much less memory than the strings), is nearly quadratic (at least for object counts greater 10000). As mentioned in my earlier posts, this quadratic behaviour is it what makes using large numbers of objects in VB infeasible. To my knowledge, memory for strings is manged by the OLE runtimes, not VB itself. This then might explain the difference. -- Ulrich Korndoerfer VB tips, helpers, solutions -> http://www.proSource.de/Downloads/
Post Follow-up to this message
Show a Printable Version
Email This Page to Someone!
Receive updates to this thread
Powered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.