As part of a WebApp I’m creating the obligatory email engine. For early testing I simply created a button that executes the following code. Which works great… but I don’t know WHY it works so well.
My question/concern is with the first few lines where I purposely create a new instance of ‘SMTPSecureSocket’ in a global variable in the App object.
If I execute this command rapidly, faster than the SMTP transaction should happen, it still seems to stack and successfully send every email! Why?! Is there something I’m not understanding about the button-down event of a WebButton? I’d have expected repeated and rapid ‘Pressed’ events to collide and cause overwriting of the App.MailSocket var/property before the socket could finish its work. Why does this continually work??
// Create new Socket
App.MailSocket = New SMTPSecureSocket
AddHandler App.MailSocket.ConnectionEstablished, AddressOf App.MailSocket_connection
AddHandler App.MailSocket.MessageSent, AddressOf App.MailSocket_message_sent
AddHandler App.MailSocket.MailSent, AddressOf App.MailSocket_mail_sent
AddHandler App.MailSocket.ServerError, AddressOf App.MailSocket_server_err
AddHandler App.MailSocket.Error, AddressOf App.MailSocket_error
// Connect to Server
App.MailSocket.Address = "smtp.<host>.com"
App.MailSocket.Port = 465
App.MailSocket.ConnectionType = SMTPSecureSocket.TLSv11
App.MailSocket.SMTPConnectionType = SMTPSecureSocket.SMTPConnectionTypes.SSLTLS
App.MailSocket.SSLEnabled = True
App.MailSocket.Username = "firstname.lastname@example.org"
App.MailSocket.Password = "<complex_pwd>"
// Create EmailMessage
Var mail As New EmailMessage
mail.FromAddress = "email@example.com>"
mail.Subject = "This email won't break!"
mail.BodyPlainText = "Happy Valentines?"
// Send it
Additionally: If I shove this code into a WebTimer, set it to execute @ 50ms intervals (Server side) and let it execute 15x in a row, every email is getting out.
Does pushing a ‘New’ Socket somehow create multiple instances, even if pointed to the same single variable?
Your os is probably buffering it and sending it out faster than you can click.
I’m old Derk, but not that old! Ha! But to your point I was suspect of the behavior of the WebButton so I put the code in a tight (50ms) loop in a timer and pushed it up to the XojoCloud (host). I’m just not certain how it keeps working, I’d think that the last iteration would work - and the prior tightly executing iterations would all step on and negate one another. Somehow they all seem to exist and persist…??
Yes. And it appears the old objects are living long enough to complete their task before being destroyed.
Note that for a web app, it would be better to make the socket a property of the session, rather than the app. If two users pressed the button at exactly the same time, you could get a collision.
Hi Tim - this is a “headless” WebApp - it’s a Web Service backend, and the emails will be generated as needed.
If you use AddHandler with WeakAddressOf instead it will probably fail I think? I’m pretty sure you’re just leaking memory like that
I’m fairly sure this is wrong. The use of AddHandler with AddressOf will retain a hard reference to the instance even when he overwrites the variable in the app. If this function is called many times you’ll be able to see memory usage increasing overtime due to the leak. AddressOf should be replaced with WeakAddressOf or explicit calls to RemoveHandler before overwriting the variable to prevent the memory leak.
That’s probably why the class is still doing it’s job? The handlers are not removed, while that should be done.
I believe this is the case yes
Yes, I must be suffering from brain freeze or too much stress or both. I’ve read that code at least three times now and did not notice the addhandler. I think I was looking for non App references.
Having said that, since the add handler is using the same reference each time, I don’t think it matters for memory leak purposes or operational purposes. It’s effectively just extra work just like setting the app.mailsocket properties each additional time.
Not true, it’s addressing the same method signature into the constructed class. Every time this class is added with new, a new instance is adding this method as it’s handler. Docs say you must always use removehandler thus… it may be (most likely) causing a leak.
Better save than sorry
A variable is just a way to acces an object (A reference), not the object itself. The object does not cease to exist just because you remove the reference to it. That is the work of the Xojo framewor, it is suposed to kill all the objects that has no references left, but, the AddHandler is creating more references to the object so, those objects are never going to be killed (memory leaking).
Anyway best practice is to have a reference per object (array dictionary, etc), use AddHandler and delegate Method to check MailSent or Error events and dispose the object and remove all the references (Nil the variable and use RemoveHandler).
Thanks everyone for helping dig into this. I’m on the fence about creating a single persistent instance of SMTPSecureSocket and feeding it a continuous queue of messages to send, or recreating SMTPSecureSocket for each separate message.
So far this seems like the cleanest method. I was leaning towards a queue of objects (array) and destroying them after their events triggered - which seems like a great way to handle memory and the asynchronous nature of socket communications.
So you’re saying if a handler is attached to some object, then that object cannot be garbage collected even when no other references exist because the associated handlers prevent it? Seems like that would defeat the purpose of ref counting in that case. How would I know if my handler needs to be removed unless I count and track the objects myself? Maybe I’m still missing something?
Yes if a handler is created with AddressOf (instead of WeakAddressOf) then a reference to that object is maintained within the framework so the object cannot be destructed. If you manually add a handler then you need to call remove handler before the object goes out of scope.
The handler IS a reference.
Well, that is the idea
Is there an easy logical way to set a breakpoint and review the stack to see if there is an accumulation of these remnants? Where would any un-garbage-collected leaks be stacking up?