Tuesday, November 4, 2008

Cyclic_proto_value JavaScript Error: What the heck is that?

I had to write about this JavaScript error as it was constant pain during some of my recent projects and it’s so hard to work out why and what causes it.

Here’s what I know about it:
After doing some research here’s what I worked out.
  1. It can pretty much pop up anywhere where OO based JavaScript is used
  1. The high level reason behind it is a cyclic reference caused by JavaScript objects incorrectly prototyping each other
Example from here:
var o1 = { p1: 1 };
var o2 = { p2: 2 };
o2.__proto__ = o1;
var o3 = { p3: 3 };
o3.__proto__ = o2;
o1.__proto__ = o3; // this hangs
You’ll notice the __proto__ property being used here instead of the standard prototype property which is used to extent objects in JavaScript. From what I understand and read on this article it an internal function that can be used to access the prototype of an object after it has been initialised via the new keyword. Not 100% sure why you would want to use this property in code but seems like a bad idea as it can cause cyclic references
  1. That being said, the __proto__ property is accessible in Mozilla’s JS engine only so you won’t see it pop up in IE or other browsers that don’t use the Mozilla JS engine

How to fix it
It’s really hard to find a solution to this problem, but bad coding and heavy JavaScript load could be the culprit, here are some possible solutions.
  1. As it is a symptom of cyclic references, it could be caused my heavy load being put on your JavaScript code by your application.
For example, we had some code that updates a DIV on the page with html code pulled from another, but this update was being done too many times and by multiple functions at around the same time, so it’s possible that one function had created a pointer to the DIV whilst another function was trying to update the same DIV.
This is most probably not the issue as the JavaScript engine should be able to handle such loads, but this in combination with external complex libraries used on the page that use OO based JavaScript coding could lead to timing issues in code execution that could lead to delays and therefore cyclic references as new objects are not created in time.
Surprisingly, we had the above coding issue with the DIV’s and after we cleaned up that code and optimised it, the Cyclic_proto_value errors being thrown by the Windows Live Messenger Library stopped! So I guess there is a connection there.
  1. Memory Leaks
Detecting memory leaks could also help you locate bad JavaScript OO coding styles and in turn locate where the cyclic references are originating from. In JavaScript, memory leaks are created when an object is created but not disposed by the JavaScript engine after it has been used. JavaScript engines do garbage collection to reclaim unused memory by collecting objects not being used or that have been set to null and then reclaiming that memory.
So bad coding could result in objects being created but somehow being overlooked by the Garbage Collector.
There are not many ‘proper’ tools out there to detect JavaScript memory leaks (Actually I’ve found nothing useful for Firefox), but Drip for IE is useful, I guess you can use it in IE and that should give you an idea if your code is suffering from memory leaks (at least in IE, but these issue could also be found in Firefox).
If you really can’t find any tools to detect the leaks or Drip is not useful enough, the good old Windows Task Manager is useful. Just open up your JavaScript application in Firefox and look at how much memory it’s consuming, during application use and after you close the application (browser tab). If you see Firefox memory use continuously increment even after you have stopped using your application then you most probably have a leak in your code. Unfortunately this approach is useless when it comes to trying to work out what in your code is causing it.
After (and if) you can locate and fix the memory leaks, that might improve the performance of your code and in turn fix the cyclic references.

Overall, this is really a hard issue with JavaScript as it can be very misleading as to what’s actually causing it. We were lucky enough to fix the issue by fixing our code performance and checking and clearing memory leaks, but this debugging phase took us more than 2 weeks and a lot was by trial and error.

If you have any comments about my explanations above, any tips on this type of error and some recommendations for testing tools please comment below.

Good luck :)

No comments:

Post a Comment

Fork me on GitHub