Forum: Ruby-core [ruby-trunk - Feature #7472][Open] Add a mechanism to remove objects from the GC cycle

Posted by sam.saffron (Sam Saffron) (Guest)
on 2012-11-30 00:49
(Received via mailing list)
Issue #7472 has been reported by sam.saffron (Sam Saffron).

----------------------------------------
Feature #7472: Add a mechanism to remove objects from the GC cycle
https://bugs.ruby-lang.org/issues/7472

Author: sam.saffron (Sam Saffron)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: 2.0.0


For typical rails apps there is a huge largely static object graph in 
memory. Requests come in, some objects are added, and the GC runs.

The blocking nature of the GC introduces a jitter that stops all 
execution.

In our typicalish Rails application, we see approximately 500k objects 
in the object space, each request add about 150k objects. On our 
production machine this means the GC stops execution for 30-40ms on a 
fairly beefy box:

GC Profiler ran during this request, if it fired you will see the cost 
below:

GC 457 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte) 
Total Object                    GC Time(ms)
    1              11.169             13134480             17014400 
425360        40.00200000000120326149
    2              11.249             13350000             17014400 
425360        32.00199999999853162080


It is clear that introducing a full scoped generational GC is a massive 
undertaking, but I was thinking that certain GC apis can make 
application servers like thin,unicorn or puma operate way more 
efficiently.

How about we add.

GC.skip(object) # remove object from GC cycle, essentially copy the ref 
to a place that is not scanned
GC.queue(object) # add an object back to the GC cycle
GC.skipped # list all the objects that are skipped


Careful use of these methods can reduce GC code by a very large amount 
as it would reduce fragmentation and logic required to determine if an 
object is alive or not.

Application servers could keep snapshots of object ids on regular 
intervals and decide which ones to skip. Sure memory usage would rise, 
but GC blocking would decrease.

Thoughts?
Posted by drbrain (Eric Hodel) (Guest)
on 2012-11-30 02:05
(Received via mailing list)
Issue #7472 has been updated by drbrain (Eric Hodel).


sam.saffron (Sam Saffron) wrote:
> How about we add.
>
> GC.skip(object) # remove object from GC cycle, essentially copy the ref to a 
place that is not scanned

What do you mean by "copy"?

If you mean "move to a different memory address" this will cause 
crashes. If a C extension has a reference to the object and you move it 
you will crash when using the old reference. If the object is referenced 
on the stack and you dereference the old location you will crash.
----------------------------------------
Feature #7472: Add a mechanism to remove objects from the GC cycle
https://bugs.ruby-lang.org/issues/7472#change-34167

Author: sam.saffron (Sam Saffron)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: 2.0.0


For typical rails apps there is a huge largely static object graph in 
memory. Requests come in, some objects are added, and the GC runs.

The blocking nature of the GC introduces a jitter that stops all 
execution.

In our typicalish Rails application, we see approximately 500k objects 
in the object space, each request add about 150k objects. On our 
production machine this means the GC stops execution for 30-40ms on a 
fairly beefy box:

GC Profiler ran during this request, if it fired you will see the cost 
below:

GC 457 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte) 
Total Object                    GC Time(ms)
    1              11.169             13134480             17014400 
425360        40.00200000000120326149
    2              11.249             13350000             17014400 
425360        32.00199999999853162080


It is clear that introducing a full scoped generational GC is a massive 
undertaking, but I was thinking that certain GC apis can make 
application servers like thin,unicorn or puma operate way more 
efficiently.

How about we add.

GC.skip(object) # remove object from GC cycle, essentially copy the ref 
to a place that is not scanned
GC.queue(object) # add an object back to the GC cycle
GC.skipped # list all the objects that are skipped


Careful use of these methods can reduce GC code by a very large amount 
as it would reduce fragmentation and logic required to determine if an 
object is alive or not.

Application servers could keep snapshots of object ids on regular 
intervals and decide which ones to skip. Sure memory usage would rise, 
but GC blocking would decrease.

Thoughts?
Posted by sam.saffron (Sam Saffron) (Guest)
on 2012-11-30 03:03
(Received via mailing list)
Issue #7472 has been updated by sam.saffron (Sam Saffron).


> if you mean "move to a different memory address" this will cause crashes.

no, not at all, leave it exactly where it is, just have objectspace 
partitioned in 2. the refs that are "skipped" don't get scanned in the 
lazy sweep.
----------------------------------------
Feature #7472: Add a mechanism to remove objects from the GC cycle
https://bugs.ruby-lang.org/issues/7472#change-34174

Author: sam.saffron (Sam Saffron)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: 2.0.0


For typical rails apps there is a huge largely static object graph in 
memory. Requests come in, some objects are added, and the GC runs.

The blocking nature of the GC introduces a jitter that stops all 
execution.

In our typicalish Rails application, we see approximately 500k objects 
in the object space, each request add about 150k objects. On our 
production machine this means the GC stops execution for 30-40ms on a 
fairly beefy box:

GC Profiler ran during this request, if it fired you will see the cost 
below:

GC 457 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte) 
Total Object                    GC Time(ms)
    1              11.169             13134480             17014400 
425360        40.00200000000120326149
    2              11.249             13350000             17014400 
425360        32.00199999999853162080


It is clear that introducing a full scoped generational GC is a massive 
undertaking, but I was thinking that certain GC apis can make 
application servers like thin,unicorn or puma operate way more 
efficiently.

How about we add.

GC.skip(object) # remove object from GC cycle, essentially copy the ref 
to a place that is not scanned
GC.queue(object) # add an object back to the GC cycle
GC.skipped # list all the objects that are skipped


Careful use of these methods can reduce GC code by a very large amount 
as it would reduce fragmentation and logic required to determine if an 
object is alive or not.

Application servers could keep snapshots of object ids on regular 
intervals and decide which ones to skip. Sure memory usage would rise, 
but GC blocking would decrease.

Thoughts?
Posted by charliesome (Charlie Somerville) (Guest)
on 2012-11-30 03:49
(Received via mailing list)
Issue #7472 has been updated by charliesome (Charlie Somerville).


What happens if an object in the 'permanent' objectspace references an 
object in the ephemeral object space?

Now this essentially becomes a generational GC and brings along all the 
implementation problems of one.
----------------------------------------
Feature #7472: Add a mechanism to remove objects from the GC cycle
https://bugs.ruby-lang.org/issues/7472#change-34182

Author: sam.saffron (Sam Saffron)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: 2.0.0


For typical rails apps there is a huge largely static object graph in 
memory. Requests come in, some objects are added, and the GC runs.

The blocking nature of the GC introduces a jitter that stops all 
execution.

In our typicalish Rails application, we see approximately 500k objects 
in the object space, each request add about 150k objects. On our 
production machine this means the GC stops execution for 30-40ms on a 
fairly beefy box:

GC Profiler ran during this request, if it fired you will see the cost 
below:

GC 457 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte) 
Total Object                    GC Time(ms)
    1              11.169             13134480             17014400 
425360        40.00200000000120326149
    2              11.249             13350000             17014400 
425360        32.00199999999853162080


It is clear that introducing a full scoped generational GC is a massive 
undertaking, but I was thinking that certain GC apis can make 
application servers like thin,unicorn or puma operate way more 
efficiently.

How about we add.

GC.skip(object) # remove object from GC cycle, essentially copy the ref 
to a place that is not scanned
GC.queue(object) # add an object back to the GC cycle
GC.skipped # list all the objects that are skipped


Careful use of these methods can reduce GC code by a very large amount 
as it would reduce fragmentation and logic required to determine if an 
object is alive or not.

Application servers could keep snapshots of object ids on regular 
intervals and decide which ones to skip. Sure memory usage would rise, 
but GC blocking would decrease.

Thoughts?
Posted by sam.saffron (Sam Saffron) (Guest)
on 2012-11-30 04:27
(Received via mailing list)
Issue #7472 has been updated by sam.saffron (Sam Saffron).


@charlie looking at the code and the heap design I think there is very 
little cheating we could do here.

I vote to close for now.

Perhaps some mechanism for optimising the freelist could give the GC a 
boost:

Something like reorder freelist so it groups on heaps ordered by 
emptiest heap first, then the lazy sweep can sweep the heaps in 
allocation order.

If you allow for a large amount of free space odds are that your lazy 
sweep could be really fast. The vast majority of stuff allocated is very 
short lived.

Anyway, any work here is going to require a huge amount of 
experimentation, the simple api I proposed is not going to be 
technically feasible, especially since RVALUEs can not be moved and the 
implications of object references causing leaks (making A permanent 
could mean you are making B,C,D,E permanent as a side effect) .

----------------------------------------
Feature #7472: Add a mechanism to remove objects from the GC cycle
https://bugs.ruby-lang.org/issues/7472#change-34187

Author: sam.saffron (Sam Saffron)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: 2.0.0


For typical rails apps there is a huge largely static object graph in 
memory. Requests come in, some objects are added, and the GC runs.

The blocking nature of the GC introduces a jitter that stops all 
execution.

In our typicalish Rails application, we see approximately 500k objects 
in the object space, each request add about 150k objects. On our 
production machine this means the GC stops execution for 30-40ms on a 
fairly beefy box:

GC Profiler ran during this request, if it fired you will see the cost 
below:

GC 457 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte) 
Total Object                    GC Time(ms)
    1              11.169             13134480             17014400 
425360        40.00200000000120326149
    2              11.249             13350000             17014400 
425360        32.00199999999853162080


It is clear that introducing a full scoped generational GC is a massive 
undertaking, but I was thinking that certain GC apis can make 
application servers like thin,unicorn or puma operate way more 
efficiently.

How about we add.

GC.skip(object) # remove object from GC cycle, essentially copy the ref 
to a place that is not scanned
GC.queue(object) # add an object back to the GC cycle
GC.skipped # list all the objects that are skipped


Careful use of these methods can reduce GC code by a very large amount 
as it would reduce fragmentation and logic required to determine if an 
object is alive or not.

Application servers could keep snapshots of object ids on regular 
intervals and decide which ones to skip. Sure memory usage would rise, 
but GC blocking would decrease.

Thoughts?
Posted by mame (Yusuke Endoh) (Guest)
on 2012-12-05 17:04
(Received via mailing list)
Issue #7472 has been updated by mame (Yusuke Endoh).

Status changed from Open to Rejected


----------------------------------------
Feature #7472: Add a mechanism to remove objects from the GC cycle
https://bugs.ruby-lang.org/issues/7472#change-34425

Author: sam.saffron (Sam Saffron)
Status: Rejected
Priority: Normal
Assignee:
Category:
Target version: 2.0.0


For typical rails apps there is a huge largely static object graph in 
memory. Requests come in, some objects are added, and the GC runs.

The blocking nature of the GC introduces a jitter that stops all 
execution.

In our typicalish Rails application, we see approximately 500k objects 
in the object space, each request add about 150k objects. On our 
production machine this means the GC stops execution for 30-40ms on a 
fairly beefy box:

GC Profiler ran during this request, if it fired you will see the cost 
below:

GC 457 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte) 
Total Object                    GC Time(ms)
    1              11.169             13134480             17014400 
425360        40.00200000000120326149
    2              11.249             13350000             17014400 
425360        32.00199999999853162080


It is clear that introducing a full scoped generational GC is a massive 
undertaking, but I was thinking that certain GC apis can make 
application servers like thin,unicorn or puma operate way more 
efficiently.

How about we add.

GC.skip(object) # remove object from GC cycle, essentially copy the ref 
to a place that is not scanned
GC.queue(object) # add an object back to the GC cycle
GC.skipped # list all the objects that are skipped


Careful use of these methods can reduce GC code by a very large amount 
as it would reduce fragmentation and logic required to determine if an 
object is alive or not.

Application servers could keep snapshots of object ids on regular 
intervals and decide which ones to skip. Sure memory usage would rise, 
but GC blocking would decrease.

Thoughts?
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.