Showing posts with label web. Show all posts
Showing posts with label web. Show all posts

Friday, July 13, 2012

JavaScript Anti-Patterns

An unfortunate side-effect of JavaScript becoming pretty much the most widely used programming language of all time is that the community has expanded in such a way that there is a lot of bad advice going around. The distribution of skills in JavaScript programmers likely varies widely (anyone have any hard data on this?). The more I study JavaScript JITs and the community, the more I realize that JavaScript is truly the assembler of our time. The big catch is that back in the days of assembler, you didn't have millions of inexperienced people putting out code.

The problem is this. So-called JavaScript patterns nearly all have to do with micro-optimizations. So many micro-optimizations have turned into folklore in the JavaScript community. Due to the inefficiency of early JavaScript interpreters, things such as hoisting array range/bounds checks have become quite widespread. If all these micro-optimizations actually made things better, no one would question the whole endeavor. However, I dare say that most beginning JavaScript programmers don't have a good handle on all the caveats and provisos which come along with each of the micro-optimizations. Micro-optimizations are being marketed as something that will always make your code faster and implicitly never breaking code. This is how beginners will understand micro-optimizations. This is unfortunately quite a bit removed from the truth. Optimizations have provisos. Modern JITs are actually quite good at squeezing every little bit of performance out of JavaScript code. It those cases where a construct cannot be optimized in general, it may be due to a lack of information, especially domain knowledge, on the part of the JIT compiler. But when the compiler doesn't optimize, the programmer cannot blindly optimize either. In the range check example, the programmer must be certain that the body of the for loop does not modify the size of the array. If this weren't the case, then checking the array length just once won't cut it.

for (var i=0, len=arr.length; i<len; i++) {
  console.log(arr[i]);
  arr.pop();
}

The above code will print out a lot of undefineds. Leaving the range check optimization to the JIT compiler would avoid this error. Fortunately, threading is not in JavaScript. If your typical JavaScript program were multi-threaded, this so-called optimization may cause even more deleterious behavior since the value of the property arr.len is no longer clear from looking only at the body of the loop.

Thursday, March 15, 2012

Garbage Collection in JavaScript, Part 1

A recent post on Scirra claimed that reusing long-lived objects was an ingredient to good JavaScript garbage collection behavior. That made me curious. This claim is generally true when the garbage collector in question is a generational one. Generational garbage collectors split the heap (memory from where all non-stack allocated things are allocated from) into several "generations". The "generational assumption" is that short-lived objects tend to be collected more frequently than long-lived objects in the heap. Upon each garbage collection, any objects which aren't collected can be promoted to the long-lived generation. The idea is that by running garbage collection less frequently on longer-lived generations, garbage collection can feel more responsive.

The problem is that generational garbage collection isn't universal. It isn't the most responsive form of garbage collection or memory management either (concurrent and incremental garbage collectors are more advanced and optimized for realtime/low-latency applications). Furthermore, although generational garbage collectors for the major browsers are in the works [Firefox, WebKit/Safari], it appears that currently only Chrome deploys one in the release browser. In fact, Chrome V8 cites generational collection as one of the main features of V8 enabling high-performance JavaScript. Around 7/20/2012, Mozilla added an Incremental Garbage Collector to Firefox 16, which reduces GC pause times by incrementalizing collection rounds, but this says nothing of and does not rely on the generation assumption. In Lisp (the first implementations of "generation" garbage collectors by Lieberman and Hewitt [PDF] and Moon [PDF]), Smalltalk (one of the first languages with generational collectors [David Ungar's paper Generation Scavenging: A Non-disruptlve High Perfornmance Storage Reclamation Algorithm, PDF]) and the higher-order typed language work (Haskell, OCaml, Standard ML, etc.), we have been using generational collectors for quite a while.

The Scirra post suggests attempting to avoid garbage collection, but that is a very tricky matter. I think the realtime performance of such an approach would be very sensitive to the design of the garbage collector and any related heuristics. Moreover, if JavaScript interpreters move beyond generational collectors at some point, programming styles exploiting the generational assumption won't have the same payoff as before.

Continue to Part 2 in this series where I introduce profiling and benchmarking features in the Chrome V8 garbage collector.

Tuesday, December 20, 2011

How long does it take to compile a web browser, Part 1

In today's brave new world, people can build and deploy a web app very quickly. However, on the other side of the equation, systems software such as web browsers are not getting any simpler. The cost of the rich media experience in modern web apps quite frequently borne by systems software including browsers, servers, and plugins. Just eyeballing, in Chrome (default multi-process mode), each tab take 30-100 MB of RAM. Luckily, I am not one to keep many tabs open concurrently, but many, many people do. A rich web experience can quickly gobble up whatever amount of memory you can throw at it. There are many people who have compared memory usage for Chrome, Firefox, Safari, and Internet Explorer (TechPP, CNet, Tom's Hardware, DotNetPerls, and many more I am sure), but, here, I would like to take a look at another facet of web browser complexity: source code size, time to build, and size of debug executable. This post follows and expands upon the type of study I did on open source finance software.

Tuesday, December 6, 2011

The Steam Engine of the 2010s?

I read a couple of technology-/startup-oriented articles recently. One was yesterday's Forbes article on developeronomics which describes the growing prominence of talented software developers and investment in them in stark terms.