Setting the heap size for production

515 views
Skip to first unread message

Mike Pearce

unread,
Mar 26, 2013, 7:10:25 PM3/26/13
to The Ruby Racer
I am deploying some production code in a Rails app that is using
therubyracer is a high throughput usage. I read that the heap size
can be limited in v0.11:
https://github.com/thefrontside/blog/blob/master/_posts/therubyracer/2012-12-04-therubyracer-rides-again.mdown.
Unfortunately, there is no indication on how to do it and it was not
clear to me looking at the code. Can anyone point me to a reference
or let me know how to do this?

Charles Lowell

unread,
Mar 26, 2013, 11:28:21 PM3/26/13
to therub...@googlegroups.com
Mike,

This is undocumented, uses a private interface, but here is some code to get you started. For some background info, V8 has a generational garbage collector which means that when objects are first allocated, they are in the young generation which is swept more aggressively. Objects that stay around longer are promoted to the old generation which are swept much less frequently. How much you should allocate for each generation depends on your app. To do so, you will instantiate a resource constraints and tell V8, in bytes, how much space to limit each memory arena. For example, here is one potential configuration that limits the memory to 144M. The default is 1.5G!

constraints = V8::C::ResourceConstraints.new
constraints.set_max_young_space_size 64 * 1024 * 1024 # 64M
constraints.set_max_old_space_size 64 * 1024 * 1024 # 64M
constraints.set_max_executable_size 16 * 1024 * 1024 # 16M
V8::C::SetResourceConstraints(constraints)


The max executable size I believe (although don't quote me) is the byte compiled and JITed code space. You can tweak these values to tune your app. Note, you need to do this *before* you initialize your very first V8::Context in order for it to have an effect.

In order to see how much V8 has allocated, you can use yet another undocumented low-level interface:

stats = V8::C::HeapStatistics.new
V8::C::V8::GetHeapStatistics(stats)
puts "total heap size: #{stats.total_heap_size}"
puts "total heap executable size: #{stats.total_heap_executable_size}"
puts "total physical size: #{stats.total_physical_size}"
puts "used heap size: #{stats.used_heap_size}"
puts "heap size limit: #{stats.heap_size_limit}"

cheers,
Charles


--
You received this message because you are subscribed to the Google Groups "The Ruby Racer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to therubyracer...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



Charles Lowell 
thefrontside.net | twitter: @cowboyd | github: cowboyd




Mike Pearce

unread,
Mar 27, 2013, 2:44:04 PM3/27/13
to The Ruby Racer
Thanks Charles. This is just what I was looking for. I'll playing
around with setting the values. The default 1.5GB heap size would
kill our production webservers (which have multiple Rails processes).

On Mar 26, 8:28 pm, Charles Lowell <cowb...@thefrontside.net> wrote:
> On Mar 26, 2013, at 6:10 PM, Mike Pearce wrote:
>
> > I am deploying some production code in a Rails app that is using
> > therubyracer is a high throughput usage.  I read that the heap size
> > can be limited in v0.11:
> >https://github.com/thefrontside/blog/blob/master/_posts/therubyracer/....
> > Unfortunately, there is no indication on how to do it and it was not
> > clear to me looking at the code.  Can anyone point me to a reference
> > or let me know how to do this?
>
> Mike,
>
> This is undocumented, uses a private interface, but here is some code to get you started. For some background info, V8 has a generational garbage collector which means that when objects are first allocated, they are in the young generation which is swept more aggressively. Objects that stay around longer are promoted to the old generation which are swept much less frequently. How much you should allocate for each generation depends on your app. To do so, you will instantiate a resource constraints and tell V8, in bytes, how much space to limit each memory arena. For example, here is one potential configuration that limits the memory to 144M. The default is 1.5G!
>
> constraints = V8::C::ResourceConstraints.new
> constraints.set_max_young_space_size 64 * 1024 * 1024 # 64M
> constraints.set_max_old_space_size 64 * 1024 * 1024 # 64M
> constraints.set_max_executable_size 16 * 1024 * 1024 # 16M
> V8::C::SetResourceConstraints(constraints)
>
> The max executable size I believe (although don't quote me) is the byte compiled and JITed code space. You can tweak these values to tune your app. Note, you need to do this *before* you initialize your very first V8::Context in order for it to have an effect.
>
> In order to see how much V8 has allocated, you can use yet another undocumented low-level interface:
>
> stats = V8::C::HeapStatistics.new
> V8::C::V8::GetHeapStatistics(stats)
> puts "total heap size: #{stats.total_heap_size}"
> puts "total heap executable size: #{stats.total_heap_executable_size}"
> puts "total physical size: #{stats.total_physical_size}"
> puts "used heap size: #{stats.used_heap_size}"
> puts "heap size limit: #{stats.heap_size_limit}"
>
> cheers,
> Charles
>
> > --
> > You received this message because you are subscribed to the Google Groups "The Ruby Racer" group.
> > To unsubscribe from this group and stop receiving emails from it, send an email to therubyracer...@googlegroups.com.
> > For more options, visithttps://groups.google.com/groups/opt_out.

Mike Pearce

unread,
Mar 27, 2013, 6:25:10 PM3/27/13
to The Ruby Racer
So i did something like this in an initializer for my Rails app:

constraints = V8::C::ResourceConstraints.new
constraints.set_max_young_space_size 5 * 1024 * 1024 # 5M
constraints.set_max_old_space_size 5 * 1024 * 1024 # 5M
constraints.set_max_executable_size 6 * 1024 * 1024 # 6M
V8::C::SetResourceConstraints(constraints)

After executing my code that uses therubyracer/V8, I get the
following:

stats = V8::C::HeapStatistics.new; V8::C::V8::GetHeapStatistics(stats)
[:heap_size_limit, :used_heap_size, :total_heap_size_executable, :total_heap_size].each_with_object({})
{|attr, acc| acc[attr] = stats.send(attr)}
#
{:heap_size_limit=>72351744, :used_heap_size=>1819440, :total_heap_size_executable=>2097152, :total_heap_size=>3018752}

The heap_size_limit, while no longer 1.5GB is still fairly large:
72MB. Is something else going on the heap other than young and old
objects and the executable? 5 + 5 + 6 definitely does not equal
72. :)

-mgp

On Mar 27, 11:44 am, Mike Pearce <chocolatecoveredm...@gmail.com>
wrote:

Charles Lowell

unread,
Mar 28, 2013, 10:11:11 AM3/28/13
to therub...@googlegroups.com
Mark,

This is purely a pass-through to the underlying V8 engine, so the resolution, if there is one, will be there.

I have two suggestions, the first is to try it from master which depends on a later version of v8 (3.16.14). Perhaps resource consumption is more faithful to the requested constraints.

Failing that, I would inquire on the v8 list what the minimum heap_size_limit is, and if there are any know inaccuracies in the built-in reporting mechanism.

I hope that helps.

cheers,
Charles

Reply all
Reply to author
Forward
0 new messages