As a result of some noticeable memory consumption problems, experienced by myself and others, I conducted a small experiment for kicks and grins. I wrote a very simple agent that contained the follow code:
Dim s As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim i As Single
Set db = s.CurrentDatabase
While True
i =i + 1
Set doc = db.CreateDocument
Print "created/deleted " & Cstr(i)
doc.Form="test"
Call doc.Save(True,False)
Call doc.Remove(True)
Wend
I then fired off about 20-30 instances of the agent, all running at the same time on the same Windows 2003 machine. I watched task manager’s memory available metric slowly works it’s way down. I have 1.1 GB, had about 970mb or so free when I started the test…It got down to about 600mb available (so 370mb seem to be consumed).
So my obvious assumption is the net affect of this code should be zero memory consumption. Because the “set doc…” set should dellocate the previous object it was pointing to before setting the reference, or am I wrong about that?
I began to think about LotusScript garbage collection, and possibly there’s a problem of cleaning up after itself fast enough (very similar to the infamous Java VM garbage collection issue).
So this food for thought, I’d appreciate any insight others may have.
Subject: RE: Should this LS code cause a memory leak?
I suspect that’s part of the problem. As posted, the loop will never finish. And with 20-30 instances running concurrently(?) I wouldn’t be too terribly surprised if it were to consume memory without releasing it – or maybe just at a faster rate than it releases it, which I suppose is why Andre wondered about using “delete”. It’s an interesting experiment though.dgg
How do you determine a memory leak? Domino does its own memory management, it is not returned to the operating system at the time you expect. But LotusScript frees memory as soon as it goes out of scope. It is very different from Java which frees memory when it ‘thinks’ it is low and when it has time. Garbage collection in Java is a low priority, in LotusScript it is a high priority task.
What happens is Java is not a memory leak. It is a low priority task. Sometimes too low (and not under Domino control). But not a leak.
I will try Andre’s suggestion of using a delete statement. I’m curious though, how is using ‘delete’ different than using ‘set obj = nothing’…
I know that Domino will “keep” memory b/c getting/returning back to the OS is an expensive process, but clearly it shouldn’t need to get “more” if has free memory within it’s management to use. If you look at my test, I’m technically only using one object reference, but it continues to chew through memory. I ran 30 instances to test simulate the workload of a transaction server…
I will try the same experiment, however incorporating the core statements inside the while loop into a sub routine, testing the theory that it should be released onced the object goes out of scope.
All of this was forced by our customers having issues with servers that a heavy application server load, i.e., many databases (a few dozen) with many agents, and on top of that running LEI with many scripts. From a CPU standpoint all looks well, but at some point the agents no longer can create an objects (i.e., we get the 'Cannot create product Object Error"…it happens over a period of 7 hours. I’ve told them to explicity set all objects to nothing when done with them, yet it still ends up with the error.
I couldn’t use Andre’s suggestion of using the DELETE statement because after calling doc.remove the object reference also was gone.
I decided to try another respondents suggestion of putting the meat of the code inside a SUB and calling that. The thought was once the objects go out of scope, the LS memory manager should clean up after itself.
THe only thing created in the initialize is the session object which I pass into the sub (so I can reference the db and create a doc)…
I am still seeing the same results. I started off with around 950mb this morning and have 10 instances of the agent running, it’s down to ~782mb, and moving downward.
As a side test, I created an agent that simply created a document,then I deleted the object reference to it by using the DELETE statement:
set doc = db.createdocument
DELETE doc
I put that in a loop and no memory is consumed, it stays pretty much constant. However obviously I am not forcing the document to save to disk, then removing it…
Subject: RE: Updated test…still seems to eat memory
if you really wanna know more details about that i’d try nsd. you can call it (with params) so it will give you a list of used domino memory objects that are currently used.
next thing: if you look for memory consumption in taskmanager only, that’s not the whole truth, from what i’ve seen only memory that is not yet swapped to disk does count here, so it might well be more more.