Investigating and Improving the Performance of Managed Language Runtime Environments

The most widely used programming languages today are managed languages. Theyare popular because their vast features improve many aspects of code development, including increased productivity and memory safety. These features are provided by the implementations of these managed languages, known as the language runtimes. Language runtimes typically consist of a variety of subsystems including interpreter(s), Just-in-Time (JIT) compiler(s), Garbage Collection (GC), and custom thread libraries. These subsystems are highly optimized as any overhead would directly affect the performance of the application’s execution. As a result, language runtimes are some of the most complex software systems today. This thesis investigates the performance implications of the language runtime environments. Specifically it fills two gaps in the understanding of runtime performance. First, there has been a lack of existing research that compares the performance in- depth of popular managed languages like JavaScript, Python and Java, to each other or to compiled languages like C++ and Go. This work first built benchmarks and instrumented the runtimes to provide an in-depth comparative analysis on the performance. This allowed us to determine which is faster (under our benchmark) as well as the source of the overhead. This work also revealed why JavaScript and Python applications scale poorly compared to other languages, and why performing GC in Java can result in a net speedup when compared with C++. This thesis further zooms in to one specific language runtime feature: memory management. Instead of proposing a new GC algorithm, we take a holistic view by examining the role of memory management in the entire systems stack. Language runtime complicates the systems stack: applications now run on top of the runtime which further runs on the OS, where both OS and runtime provide their own memory abstractions. Making matters worse, modern data analytics ecosystems are built on top of the Java Virtual Machine (JVM). As a result a data analytic application further runs on a data analytics framework that also performs its own memory management. Each of these three layers (the OS, the JVM, and the data analytics framework) performs memory management in an uncoordinated manner that often hinders each other. For example, the OS abstracts away physical memory information to provide a near infinite virtual memory space; however, the working set of data analytics applications is often so large that they should not operate on the assumption of infinite resource (as the OS swapping overhead would be too costly). This thesis provides an in-depth analysis of the gravity of this problem. We then design M3, an end-to-end system that bridges memory abstractions between layers. M3 consists of a set of mechanisms and policies allowing layers to make coordinated decisions. Applications continuously adapt to physical resource availability, and resources are distributed to competing applications according to their needs. Experiments show that compared to the best possible static configurations, M3 achieves up to 3.05x speedup.

Advisor: Yuan, Ding