dingmaotu / mql-zmq

ZMQ binding for the MQL language (both 32bit MT4 and 64bit MT5)
Apache License 2.0
543 stars 298 forks source link

Metatrader crashes (but not immediately) #37

Closed mishaxz closed 4 years ago

mishaxz commented 5 years ago

I use mql zmq on MT5 but I also used to use it on MT4 and I think I had this same problem.

After running it for a while (could be 30 minutes, could be many hours) eventually it might crash metatrader.

I have no idea how to debug this.

I use a ZMQ_POLLIN to poll a ZMQ_REQ socket continuously (with a 20ms break in between) in a timer event.

apart from the crashing everything works fine. I don't have any other EAs or scripts running in metatrader.. just the one ZMQ EA.

Can anyone think of what could be causing this? I'm on windows 10.

mishaxz commented 5 years ago

I think I may have solved it however I'm not completely sure.. I mean I changed my code and now 4 instances have run without crashing for ~2 hours which is unusual that none of them crashed.

What I did was move my Socket variable to the global scope, so instead of constantly creating a new one in my polling code - I only create it once for the EA. I also removed the ZMQ_POLLIN and use socket send/recv with true (non blocking) instead, the pollin was just a workaround to get it to timeout since I was unaware of the true parameter.

so if anyone thinks that either of these (polling using ZMQ_POLLIN or consantly creating sockets) might be the reason for metatrader crashing, please let me know. thanks.

dingmaotu commented 5 years ago

It might be some memory leak. If you are creating sockets constantly and you forgot to delete them later in your code, the memory leak might cause the crash.

It is always good practice to put context and sockets in the global scope (or better yet, create a class and make them a member variable, and delete them in destructor). Since MQL has the tradition to put everything in the OnTick or OnTimer handler, and these handlers are called many times per second, constant creation and destruction of objects is bad for performance and possibly causes memory leak.

mishaxz commented 5 years ago

thanks for the explanation, I remember now why I was creating sockets before trying to send a message.. it didn't really slow things down but it made my code more reliable, for some reason when the program hosting the zmq server code stops running, the metatrader clients stop being able to communicate it, even after that program is back up and running. But when I created new sockets before sending a message everything worked fine except for the crashes.

So do you think it would be fine for me to create sockets constantly as long as I delete them after use?

How do I actually delete a socket?

Context I always have in the global scope.

dingmaotu commented 5 years ago

If you create a socket by Socket my_socket;, it will delete it self automatically when the code goes out of current scope. If you create socket like this: Socket *my_socket = new Socket(...);, you need to delete the instance manually (delete my_socket;). But it is not recommended.

Creating sockets constantly means that the underlying connection disconnect and reconnect again and again, which is absolutely not necessary. It is just not how we write network code.

mishaxz commented 5 years ago

yes, that was what I was thinking as well - about scope. Just wanted to be sure. thanks.

I know that this is not the way it is supposed to be done, however it was a workaround to ensure stability for my use case. I do not know why if the application running NetMQ (a native C# ZeroMQ library) as a REP or ROUTER server is closed and restarted then the MQL zero mq code of my EA will not recover when the Socket is defined only once. But if it is created each time, then it works. I also wonder if this problem is caused because I'm often running VPN software, since it seems strange that zero mq would behave this way.

I mean, you can see that disconnecting and reconnecting again is why I'm using it as a workaround. This seems to be what helps it to recover from the server being restarted.

Of course I am no ZeroMQ expert, so the only reason I use this as a workaround is that I couldn't figure out another way to get it to work reliably.

dingmaotu commented 5 years ago

Another workaround may be that you recreate the socket only if you detect that the socket is disconnected. I have not done it before but I think checking the socket status is straight forward.

mishaxz commented 5 years ago

would you know how to check socket status? I want to try that but I'm not sure how to do it. I mean do you know what property I should check?

also I'm not really a great MQL expert either.. so if I wanted to recreate a global socket and reassign the variable with a new socket, do I need to use the pointer syntax you mentioned previously?