> So with about the same CPU time, JRuby will use up to 100x memory in worst case?
The JVM often trades increased memory usage for increased performance. That said "100x memory" is total hyperbole, even in the context of a microbenchmark. If you want the JVM to use less RAM, you can turn down the maximum heap size. Otherwise the heap will grow until it reaches close to full before the GC does a stop-the-world style collection of the old generation.
> Anyway Ruby 2.0 is suppose to solve the Ruby is Slow problem
Absolutely not. There are presently no plans to add a JIT compiler to the de facto Ruby interpreter.
The JVM on the other hand has the most advanced JIT compiler in the world. InvokeDynamic on Java 7 allows JRuby to do method inlining, and on Java 8 it will be able to take advantage of the full suite of HotSpot optimizations, including escape analysis and lock elision when compiling Ruby code into machine code.
No other Ruby VM will have that level of optimization.
> Otherwise the heap will grow until it reaches close to full before the GC does a stop-the-world style collection of the old generation.
Most real applications will be using ConcMarkSweepGC(or G1) and ParNewGC. With these collectors the JVM won't just burn through all the memory and halt the world unless you throw a workload at it which the GC can't handle with its normal GC cycles.
The GC makes small sweeps regularly but the duration of those sweeps is limited to ensure relatively consistent response time. If you were creating and throwing away so many objects which were promoted to the tenured generation that these small, time limited, GC sweeps couldn't keep up, then you would see the heap grow to its maximum and a 'stop the world' GC would take place. In practice that doesn't happen in the vast majority of workloads.
No, you're wrong, an extremely scant number of applications can completely avoid allocating memory in the old generation. Your best bet would probably be to use the Disruptor approach of preallocating everything then avoiding any subsequent allocations if that's really what you want to accomplish. However, if you honestly believe "most real world applications" can avoid allocating memory in the old generation, I'd sure love to see some graphs of some heap profiles of real world usage of these applications!
CMS does a stop the world collection of the old generation, however it will do an incremental collection of the eden generation. If you've ever looked at a graph of the JVM heap observing CMS running under VisualVM or YourKit, you'll notice a distinct sawtooth pattern to its collections. The diagonal parts of the sawtooth represent incremental collections in eden space. The vertical parts of the sawtooth represent stop-the-world collections of the old generation.
The "small regular sweeps" you're talking about affect the eden generation, not the old generation. Collecting the old generation is a stop the world operation in every JVM GC option except Azul's C4 collector. C4 resorts to all sorts of clever tricks to avoid stopping the world, most notably read barriers and eager pointer updates. On the Azul hardware, these tricks involved hardware transactional memory. On x86 they don't have HTM (at least until Transactional Synchronization Extensions ship on Haswell). What they do, however, is quickly set up GC invariants and a trap on a given page. Whatever thread accesses a page that contains an object which needs to be relocated relocates the object on the GC's behalf and gets the new pointer. All that said, C4 is only available on the Azul JVM, which is commercial.
CMS can't do this. It stops the world at a JVM safe point whenever it needs to collect the old generation.
CMS collector has two different types of collections it will do on the old generation. Both are "stop the world" but for drastically different amounts of time. During its 'normal' operation most of the sweep is done concurrently with two short "stop the world" points for each GC cycle. If it can't keep up, then it will do a full blow "stop the world for real" collection.
>> If you want the JVM to use less RAM, you can turn down the maximum heap size. <<
That's how the programs used to be run with JRuby 1.6.7 and with those same limits the n-body program failed to complete within 1 hour using JRuby 1.7 -- so the brittle RAM limits were abandoned.
Comments
> So with about the same CPU time, JRuby will use up to 100x memory in worst case?
The JVM often trades increased memory usage for increased performance. That said "100x memory" is total hyperbole, even in the context of a microbenchmark. If you want the JVM to use less RAM, you can turn down the maximum heap size. Otherwise the heap will grow until it reaches close to full before the GC does a stop-the-world style collection of the old generation.
> Anyway Ruby 2.0 is suppose to solve the Ruby is Slow problem
Absolutely not. There are presently no plans to add a JIT compiler to the de facto Ruby interpreter.
The JVM on the other hand has the most advanced JIT compiler in the world. InvokeDynamic on Java 7 allows JRuby to do method inlining, and on Java 8 it will be able to take advantage of the full suite of HotSpot optimizations, including escape analysis and lock elision when compiling Ruby code into machine code.
No other Ruby VM will have that level of optimization.
> Otherwise the heap will grow until it reaches close to full before the GC does a stop-the-world style collection of the old generation.
Most real applications will be using ConcMarkSweepGC(or G1) and ParNewGC. With these collectors the JVM won't just burn through all the memory and halt the world unless you throw a workload at it which the GC can't handle with its normal GC cycles.
The GC makes small sweeps regularly but the duration of those sweeps is limited to ensure relatively consistent response time. If you were creating and throwing away so many objects which were promoted to the tenured generation that these small, time limited, GC sweeps couldn't keep up, then you would see the heap grow to its maximum and a 'stop the world' GC would take place. In practice that doesn't happen in the vast majority of workloads.
No, you're wrong, an extremely scant number of applications can completely avoid allocating memory in the old generation. Your best bet would probably be to use the Disruptor approach of preallocating everything then avoiding any subsequent allocations if that's really what you want to accomplish. However, if you honestly believe "most real world applications" can avoid allocating memory in the old generation, I'd sure love to see some graphs of some heap profiles of real world usage of these applications!
CMS does a stop the world collection of the old generation, however it will do an incremental collection of the eden generation. If you've ever looked at a graph of the JVM heap observing CMS running under VisualVM or YourKit, you'll notice a distinct sawtooth pattern to its collections. The diagonal parts of the sawtooth represent incremental collections in eden space. The vertical parts of the sawtooth represent stop-the-world collections of the old generation.
The "small regular sweeps" you're talking about affect the eden generation, not the old generation. Collecting the old generation is a stop the world operation in every JVM GC option except Azul's C4 collector. C4 resorts to all sorts of clever tricks to avoid stopping the world, most notably read barriers and eager pointer updates. On the Azul hardware, these tricks involved hardware transactional memory. On x86 they don't have HTM (at least until Transactional Synchronization Extensions ship on Haswell). What they do, however, is quickly set up GC invariants and a trap on a given page. Whatever thread accesses a page that contains an object which needs to be relocated relocates the object on the GC's behalf and gets the new pointer. All that said, C4 is only available on the Azul JVM, which is commercial.
CMS can't do this. It stops the world at a JVM safe point whenever it needs to collect the old generation.
CMS collector has two different types of collections it will do on the old generation. Both are "stop the world" but for drastically different amounts of time. During its 'normal' operation most of the sweep is done concurrently with two short "stop the world" points for each GC cycle. If it can't keep up, then it will do a full blow "stop the world for real" collection.
>> If you want the JVM to use less RAM, you can turn down the maximum heap size. <<
That's how the programs used to be run with JRuby 1.6.7 and with those same limits the n-body program failed to complete within 1 hour using JRuby 1.7 -- so the brittle RAM limits were abandoned.