<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress/2.3.3" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>
<channel>
	<title>Comments on: Making Ruby&#8217;s garbage collector copy-on-write friendly</title>
	<link>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/</link>
	<description>Ecchi nanowa ikenai to omoimasu</description>
	<pubDate>Sat, 05 Jul 2008 18:43:04 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
		<item>
		<title>By: Hongli</title>
		<link>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6586</link>
		<dc:creator>Hongli</dc:creator>
		<pubDate>Fri, 27 Jul 2007 19:50:35 +0000</pubDate>
		<guid>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6586</guid>
		<description>I'm baffled. I implemented a lighweight set structure based on st.c, but the memory saving is only 500 KB instead of the expected 3.8 MB. :(</description>
		<content:encoded><![CDATA[<p>I&#8217;m baffled. I implemented a lighweight set structure based on st.c, but the memory saving is only 500 KB instead of the expected 3.8 MB. <img src='http://izumi.plan99.net/blog/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Hongli</title>
		<link>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6585</link>
		<dc:creator>Hongli</dc:creator>
		<pubDate>Fri, 27 Jul 2007 14:45:48 +0000</pubDate>
		<guid>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6585</guid>
		<description>Because a hash table entry is defined as follows:
&lt;pre lang="c"&gt;
struct st_table_entry {
    unsigned int hash;
    st_data_t key;
    st_data_t record;
    st_table_entry *next;
};
&lt;/pre&gt;
Those are 4 fields, 4 bytes each, so the size of the struct is 16 bytes. The remaining 8 bytes are malloc() memory management overhead. Since the marking table only needs a set (and not a full hash table), one can save memory by removing the 'record' (value) field. The 'hash' field also seems redundant. So by modifying st.c I can save 8 bytes per entry, though porting Google sparse_hash is probably even more efficient. And yes, malloc overhead can be solved by using a memory pool.

Perl and Python use reference counting, so they are not affected by this problem. (Though instead they have other problems, like circular references.) The Sun JVM implementation uses generational garbage collection (a modified form of mark-and-sweep) as far as I know. I'm guessing JRuby uses JVM's garbage collection.
Java is not at all affected by this problem. I'm not sure how copy-on-write friendly the Sun JVM is, but Java apps cannot fork and don't need fork, because Java apps cannot corrupt memory and because Java has excellent threading support. When a Java thread crashes, the others are unaffected.</description>
		<content:encoded><![CDATA[<p>Because a hash table entry is defined as follows:</p>
<pre lang="c">
struct st_table_entry {
    unsigned int hash;
    st_data_t key;
    st_data_t record;
    st_table_entry *next;
};
</pre>
<p>Those are 4 fields, 4 bytes each, so the size of the struct is 16 bytes. The remaining 8 bytes are malloc() memory management overhead. Since the marking table only needs a set (and not a full hash table), one can save memory by removing the &#8216;record&#8217; (value) field. The &#8216;hash&#8217; field also seems redundant. So by modifying st.c I can save 8 bytes per entry, though porting Google sparse_hash is probably even more efficient. And yes, malloc overhead can be solved by using a memory pool.</p>
<p>Perl and Python use reference counting, so they are not affected by this problem. (Though instead they have other problems, like circular references.) The Sun JVM implementation uses generational garbage collection (a modified form of mark-and-sweep) as far as I know. I&#8217;m guessing JRuby uses JVM&#8217;s garbage collection.<br />
Java is not at all affected by this problem. I&#8217;m not sure how copy-on-write friendly the Sun JVM is, but Java apps cannot fork and don&#8217;t need fork, because Java apps cannot corrupt memory and because Java has excellent threading support. When a Java thread crashes, the others are unaffected.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Giles Morant</title>
		<link>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6583</link>
		<dc:creator>Giles Morant</dc:creator>
		<pubDate>Fri, 27 Jul 2007 08:50:24 +0000</pubDate>
		<guid>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6583</guid>
		<description>Can you give a run-down of why 24 bytes are required for each entry?  Could compression (of any sort) be of use?

If malloc is the primary driver of this, how about chunking the table, much like Ruby does: e.g. the first time an entry is required, 100kb is put aside for it; the next chunk could be double etc..

Otherwise, this is a problem which must have been overcome before- what does Perl/Python/Java (JRuby?) do??

This is really interesting stuff- Ruby/Mongrel is quite intensive on memory, and this could be a winner.</description>
		<content:encoded><![CDATA[<p>Can you give a run-down of why 24 bytes are required for each entry?  Could compression (of any sort) be of use?</p>
<p>If malloc is the primary driver of this, how about chunking the table, much like Ruby does: e.g. the first time an entry is required, 100kb is put aside for it; the next chunk could be double etc..</p>
<p>Otherwise, this is a problem which must have been overcome before- what does Perl/Python/Java (JRuby?) do??</p>
<p>This is really interesting stuff- Ruby/Mongrel is quite intensive on memory, and this could be a winner.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Jamie Flournoy</title>
		<link>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6565</link>
		<dc:creator>Jamie Flournoy</dc:creator>
		<pubDate>Wed, 25 Jul 2007 15:57:35 +0000</pubDate>
		<guid>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6565</guid>
		<description>This is really exciting stuff! Keep up the good work.</description>
		<content:encoded><![CDATA[<p>This is really exciting stuff! Keep up the good work.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Andrew</title>
		<link>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6564</link>
		<dc:creator>Andrew</dc:creator>
		<pubDate>Wed, 25 Jul 2007 14:04:00 +0000</pubDate>
		<guid>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6564</guid>
		<description>I don't have any better ideas, but I wish you the best of luck Hongli. Good work.</description>
		<content:encoded><![CDATA[<p>I don&#8217;t have any better ideas, but I wish you the best of luck Hongli. Good work.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Hongli</title>
		<link>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6563</link>
		<dc:creator>Hongli</dc:creator>
		<pubDate>Wed, 25 Jul 2007 13:22:31 +0000</pubDate>
		<guid>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6563</guid>
		<description>Thanks. :)

Sure, here's the pmap output just after forking:
&lt;pre&gt;13639:   ./trunk/ruby test.rb
Address   Kbytes Mode  Offset           Device    Mapping
08048000     712 r-x-- 0000000000000000 008:00006 ruby
080fa000       4 rw--- 00000000000b2000 008:00006 ruby
080fb000   16828 rw--- 00000000080fb000 000:00000   [ anon ]
b714b000    7160 rw--- 00000000b714b000 000:00000   [ anon ]
b7849000    2104 rw--- 00000000b7bdd000 000:00000   [ anon ]
b7c45000    1188 rw--- 00000000b7c45000 000:00000   [ anon ]
b7d6e000    1260 r-x-- 0000000000000000 008:00011 libc-2.5.so
b7ea9000       4 r---- 000000000013b000 008:00011 libc-2.5.so
b7eaa000       8 rw--- 000000000013c000 008:00011 libc-2.5.so
b7eac000      12 rw--- 00000000b7eac000 000:00000   [ anon ]
b7eaf000     148 r-x-- 0000000000000000 008:00011 libm-2.5.so
b7ed4000       8 rw--- 0000000000024000 008:00011 libm-2.5.so
b7ed6000       4 rw--- 00000000b7ed6000 000:00000   [ anon ]
b7ed7000      20 r-x-- 0000000000000000 008:00011 libcrypt-2.5.so
b7edc000       8 rw--- 0000000000004000 008:00011 libcrypt-2.5.so
b7ede000     156 rw--- 00000000b7ede000 000:00000   [ anon ]
b7f05000       8 r-x-- 0000000000000000 008:00011 libdl-2.5.so
b7f07000       8 rw--- 0000000000001000 008:00011 libdl-2.5.so
b7f1f000      16 rw--- 00000000b7f1f000 000:00000   [ anon ]
b7f23000     100 r-x-- 0000000000000000 008:00011 ld-2.5.so
b7f3c000       8 rw--- 0000000000019000 008:00011 ld-2.5.so
bffa4000      84 rw--- 00000000bffa4000 000:00000   [ stack ]
ffffe000       4 r-x-- 0000000000000000 000:00000   [ anon ]
mapped: 29852K    writeable/private: 27596K    shared: 0K&lt;/pre&gt;
And this is the output after garbage collection:
&lt;pre&gt;13639:   ./trunk/ruby test.rb
Address   Kbytes Mode  Offset           Device    Mapping
08048000     712 r-x-- 0000000000000000 008:00006 ruby
080fa000       4 rw--- 00000000000b2000 008:00006 ruby
080fb000   18940 rw--- 00000000080fb000 000:00000   [ anon ]
b714b000    7160 rw--- 00000000b714b000 000:00000   [ anon ]
b7849000    2104 rw--- 00000000b7bdd000 000:00000   [ anon ]
b7c45000    1188 rw--- 00000000b7c45000 000:00000   [ anon ]
b7d6e000    1260 r-x-- 0000000000000000 008:00011 libc-2.5.so
b7ea9000       4 r---- 000000000013b000 008:00011 libc-2.5.so
b7eaa000       8 rw--- 000000000013c000 008:00011 libc-2.5.so
b7eac000      12 rw--- 00000000b7eac000 000:00000   [ anon ]
b7eaf000     148 r-x-- 0000000000000000 008:00011 libm-2.5.so
b7ed4000       8 rw--- 0000000000024000 008:00011 libm-2.5.so
b7ed6000       4 rw--- 00000000b7ed6000 000:00000   [ anon ]
b7ed7000      20 r-x-- 0000000000000000 008:00011 libcrypt-2.5.so
b7edc000       8 rw--- 0000000000004000 008:00011 libcrypt-2.5.so
b7ede000     156 rw--- 00000000b7ede000 000:00000   [ anon ]
b7f05000       8 r-x-- 0000000000000000 008:00011 libdl-2.5.so
b7f07000       8 rw--- 0000000000001000 008:00011 libdl-2.5.so
b7f1f000      16 rw--- 00000000b7f1f000 000:00000   [ anon ]
b7f23000     100 r-x-- 0000000000000000 008:00011 ld-2.5.so
b7f3c000       8 rw--- 0000000000019000 008:00011 ld-2.5.so
bffa4000      84 rw--- 00000000bffa4000 000:00000   [ stack ]
ffffe000       4 r-x-- 0000000000000000 000:00000   [ anon ]
mapped: 31964K    writeable/private: 29708K    shared: 0K&lt;/pre&gt;</description>
		<content:encoded><![CDATA[<p>Thanks. <img src='http://izumi.plan99.net/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Sure, here&#8217;s the pmap output just after forking:</p>
<pre>13639:   ./trunk/ruby test.rb
Address   Kbytes Mode  Offset           Device    Mapping
08048000     712 r-x-- 0000000000000000 008:00006 ruby
080fa000       4 rw--- 00000000000b2000 008:00006 ruby
080fb000   16828 rw--- 00000000080fb000 000:00000   [ anon ]
b714b000    7160 rw--- 00000000b714b000 000:00000   [ anon ]
b7849000    2104 rw--- 00000000b7bdd000 000:00000   [ anon ]
b7c45000    1188 rw--- 00000000b7c45000 000:00000   [ anon ]
b7d6e000    1260 r-x-- 0000000000000000 008:00011 libc-2.5.so
b7ea9000       4 r---- 000000000013b000 008:00011 libc-2.5.so
b7eaa000       8 rw--- 000000000013c000 008:00011 libc-2.5.so
b7eac000      12 rw--- 00000000b7eac000 000:00000   [ anon ]
b7eaf000     148 r-x-- 0000000000000000 008:00011 libm-2.5.so
b7ed4000       8 rw--- 0000000000024000 008:00011 libm-2.5.so
b7ed6000       4 rw--- 00000000b7ed6000 000:00000   [ anon ]
b7ed7000      20 r-x-- 0000000000000000 008:00011 libcrypt-2.5.so
b7edc000       8 rw--- 0000000000004000 008:00011 libcrypt-2.5.so
b7ede000     156 rw--- 00000000b7ede000 000:00000   [ anon ]
b7f05000       8 r-x-- 0000000000000000 008:00011 libdl-2.5.so
b7f07000       8 rw--- 0000000000001000 008:00011 libdl-2.5.so
b7f1f000      16 rw--- 00000000b7f1f000 000:00000   [ anon ]
b7f23000     100 r-x-- 0000000000000000 008:00011 ld-2.5.so
b7f3c000       8 rw--- 0000000000019000 008:00011 ld-2.5.so
bffa4000      84 rw--- 00000000bffa4000 000:00000   [ stack ]
ffffe000       4 r-x-- 0000000000000000 000:00000   [ anon ]
mapped: 29852K    writeable/private: 27596K    shared: 0K</pre>
<p>And this is the output after garbage collection:</p>
<pre>13639:   ./trunk/ruby test.rb
Address   Kbytes Mode  Offset           Device    Mapping
08048000     712 r-x-- 0000000000000000 008:00006 ruby
080fa000       4 rw--- 00000000000b2000 008:00006 ruby
080fb000   18940 rw--- 00000000080fb000 000:00000   [ anon ]
b714b000    7160 rw--- 00000000b714b000 000:00000   [ anon ]
b7849000    2104 rw--- 00000000b7bdd000 000:00000   [ anon ]
b7c45000    1188 rw--- 00000000b7c45000 000:00000   [ anon ]
b7d6e000    1260 r-x-- 0000000000000000 008:00011 libc-2.5.so
b7ea9000       4 r---- 000000000013b000 008:00011 libc-2.5.so
b7eaa000       8 rw--- 000000000013c000 008:00011 libc-2.5.so
b7eac000      12 rw--- 00000000b7eac000 000:00000   [ anon ]
b7eaf000     148 r-x-- 0000000000000000 008:00011 libm-2.5.so
b7ed4000       8 rw--- 0000000000024000 008:00011 libm-2.5.so
b7ed6000       4 rw--- 00000000b7ed6000 000:00000   [ anon ]
b7ed7000      20 r-x-- 0000000000000000 008:00011 libcrypt-2.5.so
b7edc000       8 rw--- 0000000000004000 008:00011 libcrypt-2.5.so
b7ede000     156 rw--- 00000000b7ede000 000:00000   [ anon ]
b7f05000       8 r-x-- 0000000000000000 008:00011 libdl-2.5.so
b7f07000       8 rw--- 0000000000001000 008:00011 libdl-2.5.so
b7f1f000      16 rw--- 00000000b7f1f000 000:00000   [ anon ]
b7f23000     100 r-x-- 0000000000000000 008:00011 ld-2.5.so
b7f3c000       8 rw--- 0000000000019000 008:00011 ld-2.5.so
bffa4000      84 rw--- 00000000bffa4000 000:00000   [ stack ]
ffffe000       4 r-x-- 0000000000000000 000:00000   [ anon ]
mapped: 31964K    writeable/private: 29708K    shared: 0K</pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: Pratik</title>
		<link>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6562</link>
		<dc:creator>Pratik</dc:creator>
		<pubDate>Wed, 25 Jul 2007 13:05:07 +0000</pubDate>
		<guid>http://izumi.plan99.net/blog/index.php/2007/07/25/making-rubys-garbage-collector-copy-on-write-friendly/#comment-6562</guid>
		<description>I think sparse_hash sounds like a good trade-off of speed/memory usage. Also, it'd be awesome if you could post pasties of "pmap -d " output. I don't really know about "GNOME System Monitor" and only thing I trust with calculating memory usage is pmap :)

You're super cool in any case (even if you fail) ! Amazing job.

Thanks.</description>
		<content:encoded><![CDATA[<p>I think sparse_hash sounds like a good trade-off of speed/memory usage. Also, it&#8217;d be awesome if you could post pasties of &#8220;pmap -d &#8221; output. I don&#8217;t really know about &#8220;GNOME System Monitor&#8221; and only thing I trust with calculating memory usage is pmap <img src='http://izumi.plan99.net/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>You&#8217;re super cool in any case (even if you fail) ! Amazing job.</p>
<p>Thanks.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
