IWETHEY v. 0.3.0 | TODO
1,095 registered users | 0 active users | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New Two letters: GC
Java finally introduced it into mainstream. PHBs no longer faint dead when they hear that "delete" is not used.
--

Less Is More. In my book, About Face, I introduce over 50 powerful design axioms. This is one of them.

--Alan Cooper. The Inmates Are Running the Asylum
New So?
Again, how is this a step up? I never had any issues deleting things. A good programmer, like a good boy scout, doesn't spread garbage around. In fact I've *never understood* GC as even a worthwhile topic.

Are you telling me that common C++ implementations would hit heap exhaustion even with correct use of deletion?

Is GC enough to justify all the BS and overhead?

In the days of FORTRAN one did accurate capacity planning based on actual declared storage, then doubled it, when approximating how much memory a program would need in production. This allowed for quick addition of other functions as needed. We did "garbage prevention".

I submit that a GCed system often hides ridiculous object whoppers that would be instantly obvious in C++ (say, runaway allocation). I'd be willing to bet *without knowing a damn thing about it* that in practice, Java GC must amount to some significant percentage in processing time - let me guess, 15 percent.

GC is another stupid computer "science" abstraction designed by ivory-tower dwellers.
-drl
New GC is totally worth it and can be *more* efficient
than manual memory management. Even in a simple C type environment where you can pretty much keep track of what's going on. C++ really *needs* a GC because there are about a half dozen ways to allocate and free memory (actually they've cut down a bit by at least eliminating the error prone delete [] ). Just forgetting to declare a base class's destructor virtual has lead to more leaks than the Titanic. There have been more than a handful of C++ projects that were "saved" by introducing a GC library.

There are a number of slick GC algorithms and the topic is a worthwhile study in itself. Here's a good [link|http://www.amazon.com/exec/obidos/tg/detail/-/0471941484/qid=1080176255/sr=1-1/ref=sr_1_1/102-9009744-0068150?v=glance&s=books|book] on the topic.

The reason GC can be more efficient is you don't necessarily have to figure out what to throw away - you only have to figure out what to keep - that is often a much smaller set. The Objective C crowd uses a primitive GC system called AutoReleasePools that are constructed on the stack - the newest pool creates a sort of "scope" and hangs on to all allocated objects. When the pool is released, all objects that have reference count of zero are collected and the rest handed to the parent pool to watch. An autorelease pool is created for each event delivery in a regular gui application and each web request in a web app. This creates a nice automatic cycle of memory mangement.

GC got a bad rap because the early lisp systems had very primitive GC algorithms and would frequently halt for several seconds cleaning things up. This was annoying. Smalltalk has used GC from day one. Several different GC approaches were developed using Smalltalk and any modern Smalltalk system uses several different algorithms in concert to provide optimal performance - largely by dividing memory into "new space" and "old space". Hard realtime systems have been done by using bounded incremental GC.

Java started out with abysmal GC (gotta invent everything from scratch in the Java world - no need to look at other systems dontcha know) and has gotten a little better with each release. Right now I'd say the 1.4 implementation is more or less adequate (although cheapbastards.com runs on Java 1.3.0 because something they've done can't cope with the new GC implementation in even 1.3.1 much less 1.4 where they changed everything around).

I think GC is totally sensible - let the machine manage what its good at, let me do the tricky bits. Worst thing I can say about GC is that it has allowed a number of no-talent ass clowns to enter the main stream and call themselves developers.



Java is a joke, only it's not funny.

     --Alan Lovejoy
Expand Edited by tuberculosis Aug. 21, 2007, 06:02:19 AM EDT
New Ok I'll accept that
I'll read up and see if what my gut says then matches what my head says. I'd like some history links if you can find'em.

My gut says discipline in creating the program so that it does predictable things is the most important factor.
-drl
New I like ObjectiveC's memory management.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Its sort of NGC
Near Garbage Collection. Technically it *is* GC but the need to do release/retain is rather tedious. I think the GnuStep guys added the boehm collector or something to make it more automated.



Java is a joke, only it's not funny.

     --Alan Lovejoy
Expand Edited by tuberculosis Aug. 21, 2007, 06:03:11 AM EDT
New Kinda tedious, but not really.
I like knowing when that stuff is going away sometimes.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Reigning in the beast
The reason GC can be more efficient is you don't necessarily have to figure out what to throw away - you only have to figure out what to keep - that is often a much smaller set.

On the other hand, you can beat you head against the wall sometimes trying to keep it from deleting something you need.

I remember a discussion I wandered past where several developers were discussing options on how to keep a static object created during startup from being GC'ed by C# in an embedded environment. The object kept configuration information in it, and may or may not be used depending on the particular use case employed. Apparently (and I am most steadfastly not a C-pigpen expert), just declaring this instance a static instance was not sufficient to keep the GC at bay. The reason had something to do with the fact that this was an embedded environment, and the program (and the object) just sort of 'was', as opposed to being explicitly started through the standard wonder of crt0 (or its C-pigpen equivalent). This led the GC to sudeently realize that there was this object, see, that nobody seemed to be using, so it must therefore be gobbige, sooo...execute the Electrolux algorithm (and remember, Nothing Sucks Like an Electrolux).

I'm with Ross on this one (but you already knew that, din'cha?).
jb4
shrub\ufffdbish (Am., from shrub + rubbish, after the derisive name for America's 43 president; 2003) n. 1. a form of nonsensical political doubletalk wherein the speaker attempts to defend the indefensible by lying, obfuscation, or otherwise misstating that facts; GIBBERISH. 2. any of a collection of utterances from America's putative 43rd president. cf. BULLSHIT
New Whoa
I'm out of my league with TB - so what he says gets counted 10 times over. But my intuitive sense is that a properly "objectified" problem will never need GC, that simple scoping should handle such things. If you need something to be really persistent, then make it global. Is there really a "middle ground"? Either something is or isn't persistent. Things are never "partially persistent".

But of course Todd will (I hope) explain to me why I'm full of shit :)
-drl
New "Partially persistant" things happen all of the time
Consider Apache running an embedded interpreter like mod_perl. A lot of data persists for one Apache request cycle, no more, no less. It is not allocated at the start of the request cycle - the code that allocates it is nowhere near Apache. In fact the code that allocates it may be in modules that know nothing about Apache (which can be used offline as well). But somehow we need to properly discover at runtime that this data is to survive one request cycle.

We don't want the data to be permanent, because then we could not serve very many pages per process. We don't want it to go away promptly, because then we wouldn't still have the data when the time comes to send output. It very strongly needs to be partially persistent.

GC is an effective way to accomplish that without making a lot of assumptions about your running environment. If you want to work without some form of GC, well it is possible, but you need to assume lots about your environment. For instance look at the different memory pools in Apache - places where partially persistent things with different lifetimes get allocated so that they can be promptly deallocated when the time comes.

Sure, that works. But code written to be embedded in such a system is not so easy to include in another system that does memory management differently. Not because there is a serious incompatibility, but just because the decision to manage memory manually allows all sorts of gratiutous incompatibilities. (And the full-blown solution used by Apache is far more complex than most products would want.)

If this doesn't convince you, then consider the following. The trend is to make computer time cheaper and cheaper. If the programmer is more valuable than the computer, then it makes sense to have the computer do a lot of work so that the programmer doesn't have to. It doesn't matter how much you, personally, like or dislike this point of view. As long as computers get faster and programmers don't, economics will make more get handed off to the computer. GC is only one of many ways in which this happens.

Cheers,
Ben
"good ideas and bad code build communities, the other three combinations do not"
- [link|http://archives.real-time.com/pipermail/cocoon-devel/2000-October/003023.html|Stefano Mazzocchi]
New I am confused totally
what ever happened to
do foo return stack in mem
end foo release stack in mem
is it the RAD's or laziness or the inability to return the memory pointers, I havnt done c++ since 95 so please forgive any ignorance of the levels the language is at now.
thanx,
bill
In Bush\ufffds America, fighting terrorism abroad is used as a pretext for vanquishing civil liberties at home. David Podvin
questions, help? [link|mailto:pappas@catholic.org|email pappas at catholic.org]
New Its the heap
Foo* f = new Foo();
//do stuff
delete f;

Seems simple, right? Unless something in do stuff throws and exception that prevents the delete f line from being executed. This happened in C++ all the time. The answer is to never use raw pointers - use an auto_ptr or some pretend pointer object on the stack. Objects on the stack get their destructors called when going out of scope - no matter what. Objects on the heap are your problem. The trick is to use little stack objects' lifetimes to manage the lifetimes of heap objects.

It works OK if you never use a raw pointer in C++. Sadly, lots of people still use raw pointers.



Java is a joke, only it's not funny.

     --Alan Lovejoy
Expand Edited by tuberculosis Aug. 21, 2007, 06:10:30 AM EDT
New You can't use the stack for a lot of things
Data structures created on the stack can't be returned. Which blocks many important programming techniques. An example of why you want data not to be on the stack in Apache is that there are routines whose purpose is to read the configuration file. The data structures created should survive - until you re-read the configuration again.

Todd points out why a naive stack-based approach can run into problems. But the "smart pointers" approach that he suggests won't work for Apache for a number of reasons, prominent among them being the fact that Apache is written in C, not C++.

Apache's solution is to have a set of memory pools, each of which is cleaned up at predictable points in the Apache process. For instance one pool is cleaned up every time you re-read the configuration file (which is where the above data structure assigned while reading the configuration would be assigned), while another is cleaned up after finishing processing a request (guess where the page to be returned is built up?). Whenever you allocate data, you decide which kind of data you have, and allocate from the correct pool. If you want, you can also put a clean-up hook on that pool. (The latter hooks are completely available to embedded interpreters as of Apache 2.0.) When that point arrives, that pool is cleaned out.

This works well for Apache's problem space. But obviously not every application will do things that way, and those that do won't have exactly the same pools that Apache does...

Adding garbage collection stops this kind of difference from being a programmer design decision, eliminates a lot of errors, and makes code more likely to be shareable. (Using reference counting works pretty well - Perl does it with some success - but the farther you push reference counting, the more that you notice the flaws.)

Cheers,
Ben
"good ideas and bad code build communities, the other three combinations do not"
- [link|http://archives.real-time.com/pipermail/cocoon-devel/2000-October/003023.html|Stefano Mazzocchi]
New Re: You can't use the stack for a lot of things
Ben said:

Apache's solution is to have a set of memory pools, each of which is cleaned up at predictable points in the Apache process. For instance one pool is cleaned up every time you re-read the configuration file (which is where the above data structure assigned while reading the configuration would be assigned), while another is cleaned up after finishing processing a request (guess where the page to be returned is built up?). Whenever you allocate data, you decide which kind of data you have, and allocate from the correct pool. If you want, you can also put a clean-up hook on that pool. (The latter hooks are completely available to embedded interpreters as of Apache 2.0.) When that point arrives, that pool is cleaned out.

Odd, this is exactly how Todd suggested I deal with the large tables of calculated perturbations that go with an accurate planetary position, if you have a variable number of instances of the same planet.
-drl
New A good design is a good design...
"good ideas and bad code build communities, the other three combinations do not"
- [link|http://archives.real-time.com/pipermail/cocoon-devel/2000-October/003023.html|Stefano Mazzocchi]
New Ah, I see...
Basing your opinion of GC on the behavior of, let me get this straight, C#, was it? In an embedded environment, no less, where MS is at its finest...

Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New OK, OK,...Fair enough
Don't misunderstand, I don't hate GC per se. I just don't see what all the fuss is about. From other posts in this thread, we have found that (according to The Toddster):
Just forgetting to declare a base class's destructor virtual has lead to more leaks than the Titanic. There have been more than a handful of C++ projects that were "saved" by introducing a GC library.

Which gets parsed and translated by my aberrant brain as
GC has saved many less-than-adequate programmers from having to fix their bugs at their source, by simply throwing a rug over the gaping holes in their less-than-adequate knowledge and less-than-adequate discipline
(Not that Todd needs me to put words into his mouth! ;-) )

So what is the goal here? To get something, anything out the door as quickly as possible; damn the torpedoes, full speed ahead (aka, the PHB credo)? Or is it to write good, well-formed, proper code the first time (or the second time, or the third time, if necessary) so that when it inevitably needs to be extended, that can be gotten out the door as quickly as possible (aka, the engineer's credo)?

I bet I know which one Tata wants....
jb4
shrub\ufffdbish (Am., from shrub + rubbish, after the derisive name for America's 43 president; 2003) n. 1. a form of nonsensical political doubletalk wherein the speaker attempts to defend the indefensible by lying, obfuscation, or otherwise misstating that facts; GIBBERISH. 2. any of a collection of utterances from America's putative 43rd president. cf. BULLSHIT
New The world is full of less-than-adequate programmers
its the norm dontcha know.

Anyhow, not having a delete used to bug me - now I relax and just figure what I allocate will go away by the next cycle (event, web request, whatever) if I don't take special measures to keep it. This seems pretty sensible to me.

o what is the goal here?

To ship working software asap. That is and has always been the goal.



Java is a joke, only it's not funny.

     --Alan Lovejoy
Expand Edited by tuberculosis Aug. 21, 2007, 06:10:32 AM EDT
New And plain ol' automation is the mechanism
jb4: what is the goal here?
Todd: To ship working software asap. That is and has always been the goal.

The means to that end being: if it's something the programmer *must* do *every* time, automate it. Are there exceptions? Sure, but most software that does get shipped (meaning off-the-shelf stuff) benefits from GC. If your app needs manual memory management, don't use automatic GC.
New Don't get it.
How did you keep a reference to that object?

If there is a reference to it, GCing it would be a bug... If there is no reference to it, how do you know the difference?
--

Less Is More. In my book, About Face, I introduce over 50 powerful design axioms. This is one of them.

--Alan Cooper. The Inmates Are Running the Asylum
New Circular references and Class GC
Like in Java 1.02. If the only reference to an object is its class, and there are no references to the class active, then its a circular reference and the whole assembly is a candidate for collection. Which is why classgc is not such a great idea.



Java is a joke, only it's not funny.

     --Alan Lovejoy
Expand Edited by tuberculosis Aug. 21, 2007, 06:10:35 AM EDT
New Still don't get it...
How is a class a reference to object? Static member can be...
--

Less Is More. In my book, About Face, I introduce over 50 powerful design axioms. This is one of them.

--Alan Cooper. The Inmates Are Running the Asylum
New I guess now I do
Garbage-collecting class - what a stupid idea!

As long as there is a single line of code that can possibly reference them, those things cannot be collected. GC that only counts references from stack is G.
--

Less Is More. In my book, About Face, I introduce over 50 powerful design axioms. This is one of them.

--Alan Cooper. The Inmates Are Running the Asylum
New Think singleton
instances reference class - makes sense, in singleton a static references the single instance. Nice circular package that nothing else is referencing for awhile - so it gets GC'd.

Way dumb.



Java is a joke, only it's not funny.

     --Alan Lovejoy
Expand Edited by tuberculosis Aug. 21, 2007, 06:12:12 AM EDT
New Translate into non comp-sci jargon?
-drl
New Singleton is a pattern
Consider where you think you have an object that represents a single thing. Like the keyboard. You have two options - you can make all the methods to deal with the keyboard class methods. After all there is only one and what sense does it make to have programmers allocating Keyboards willy nilly? So you make all the methods class methods and the class object itself represents THE keyboard.

This sounds great - until USB arrives and you want to write a two player game letting each player have his own keyboard. Now you've got potentially several keyboards and the keyboard class you wrote is junk - you can't use it.

So we hedge our bets - we actually create a keyboard class but put all the behavior on the instance side. Then we make the class responsible for determining how many keyboards there can be and what the allocation policy is. For conventional single keyboard apps you implement singleton. There is exactly one instance of the Keyboard and you ask the class for it.

In Java this looks like this:

public class Keyboard
{
// make the constructor private - only the class can call it
private Keyboard() { ... }

// keep a copy of the singleton
static _instance;

// provide a way to get the singleton - construct only if asked for
public static instance()
{
if(null == _instance) _instance = new Keyboard();
return _instance;
}
...
}

When you get to your game, you only have to tweak the class a little like:

private Keyboard
{
Keyboard _player1();
Keyboard _player2();

public static Keyboard player1()
{
if(null == _player1) blah blah blah

}

you get the idea. You use the class to control how many instances of a class exist.

The problem I alluded to is that - with the class instance variable being the only reference to the object, and the object being the only reference to the class, the GC concluded nobody else would care if the thing went away. This is basically true - but one win to singletons is you initialize them once and they sit there all warmed up and ready to use. Collecting the class caused a lot of thrashing of initialization code.

Stupid Java people.



Java is a joke, only it's not funny.

     --Alan Lovejoy
Expand Edited by tuberculosis Aug. 21, 2007, 06:12:42 AM EDT
New Translation
Sometimes you want an expensive to compute thing to be available in many places. A standard way to do it is to create a class that will only produce one object. If you call the class' constructor, it will produce and save the object only if it doesn't exist, then return it. On the second call it just returns it. This is called a singleton because there is a single instance of the class.

The problem is that when one person has used the singleton you have an object that exists which isn't referenced outside the class. A good GC algorithm would detect that the object is still in use and shouldn't be destroyed. In real software, the object can get detected as garbage and destroyed, forcing you to create it again. Not desired since not having to create it again and again was, after all, the point of creating singleton.

Cheers,
Ben
"good ideas and bad code build communities, the other three combinations do not"
- [link|http://archives.real-time.com/pipermail/cocoon-devel/2000-October/003023.html|Stefano Mazzocchi]
New This was a problem in Java 1.02 as well
Which might say somtehing about the state of C#.

I recall there was a problem with 1.02 collecting Classes that the runtime thought were not needed. This resulted in expensively allocated singletons vanishing and inconvenient times and performance hits initializing all new singletons when they were referenced again.

Yes it sucked and was stupid. The workaround at the time was to launch the VM with --no-class-gc (something like that). I think this is now the default. Classes ought not to be subject to GC or ought to be held strongly by their ClassLoader (the latter is probably best).



Java is a joke, only it's not funny.

     --Alan Lovejoy
Expand Edited by tuberculosis Aug. 21, 2007, 06:10:26 AM EDT
New Re: This was a problem in Java 1.02 as well
Obviously, this was a problem with an earlier version of Java that does not have the problem any more (of course, you trade this problem for the new classloader problem of today).

However, I did not realize that .NET (the underlying CLR, I should say) had this same problem. Is this by design or just another bug? I wonder if it's still there as part of the 1.1 version of .NET. If so, I wonder how they will solve it (Java solved it by creating a parent/child relationship between classloaders, but this caused other problems).

Dan
New Could you elaborate on classloader problem?
<shame>I don't know what it is</shame>
--

Less Is More. In my book, About Face, I introduce over 50 powerful design axioms. This is one of them.

--Alan Cooper. The Inmates Are Running the Asylum
New Re: Could you elaborate on classloader problem?
The basic issue is how the new (as in JDK 1.2 and more recent) classloaders work. Here's a good explanation of the issue here: [link|http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html|http://www.javaworld...qa-0606-load.html]

Dan
New As the article says,
"Those class and resource loading strategies must be the most poorly documented and least specified area of J2SE."

Since I only deal with Java applications and applets, I normally don't encounter any of the problems described. But, it was an entertaining read. Thank you.
--

Less Is More. In my book, About Face, I introduce over 50 powerful design axioms. This is one of them.

--Alan Cooper. The Inmates Are Running the Asylum
New what does Guitar Center have to do with this? :)
-----
Steve
New Re: what does Guitar Center have to do with this? :)
The electric guitar has "music garbage note collection" where you turn a mistake into a spine-chilling riff. The piano under JS Bach, alas, has no such facility.
-drl
New Yes, and in the hands of a Master
like Jimi, the difference between a mistake and audio nirvana (not Nirvana, who do not qualify as Masters) is nil.

In Java, the difference between a mistake and nirvana is...well, H U G E !
jb4
shrub\ufffdbish (Am., from shrub + rubbish, after the derisive name for America's 43 president; 2003) n. 1. a form of nonsensical political doubletalk wherein the speaker attempts to defend the indefensible by lying, obfuscation, or otherwise misstating that facts; GIBBERISH. 2. any of a collection of utterances from America's putative 43rd president. cf. BULLSHIT
New Java has gonorrhea? Or Java == gonorrhea? I'd buy either.
bcnu,
Mikem

The soul and substance of what customarily ranks as patriotism is moral cowardice and always has been...We have thrown away the most valuable asset we had-- the individual's right to oppose both flag and country when he (just he, by himself) believed them to be in the wrong. We have thrown it away; and with it all that was really respectable about that grotesque and laughable word, Patriotism.

- Mark Twain, "Monarchical and Republican Patriotism"
     Java skills gap - (bluke) - (59)
         Re: Java skills gap - (deSitter) - (10)
             Believe me I know - (bluke) - (9)
                 Re: Believe me I know - (deSitter) - (8)
                     Makes sense, so it won't happen. -NT - (mmoffitt)
                     Not so easy to find a savvy person either - (bluke) - (6)
                         Re: Not so easy to find a savvy person either - (deSitter) - (5)
                             Because HR screens resumes - (bluke) - (4)
                                 Definitely agree on that last point. - (admin) - (3)
                                     The best thing I ever did was learn Smalltalk - (bluke) - (2)
                                         I dont know, but as long as they bathe regular I dont mind - (boxley)
                                         Great interview question: - (admin)
         I am afraid there is even more - (Arkadiy) - (45)
             This is why I am not a big fan of IDE's - (bluke) - (44)
                 Disagree slightly. - (mmoffitt) - (43)
                     GUI IDEs just get in my way - (admin) - (1)
                         I hate doing UI's. - (mmoffitt)
                     Intelij is a perfect example - (bluke) - (40)
                         Funny, I've found Java itself "awful" :-) -NT - (mmoffitt) - (39)
                             It is, but IntelliJ makes it less miserable -NT - (tuberculosis)
                             It all depends on where you are coming from - (bluke) - (37)
                                 Re: It all depends on where you are coming from - (deSitter) - (36)
                                     Two letters: GC - (Arkadiy) - (35)
                                         So? - (deSitter) - (30)
                                             GC is totally worth it and can be *more* efficient - (tuberculosis) - (29)
                                                 Ok I'll accept that - (deSitter)
                                                 I like ObjectiveC's memory management. -NT - (admin) - (2)
                                                     Its sort of NGC - (tuberculosis) - (1)
                                                         Kinda tedious, but not really. - (admin)
                                                 Reigning in the beast - (jb4) - (24)
                                                     Whoa - (deSitter) - (6)
                                                         "Partially persistant" things happen all of the time - (ben_tilly) - (5)
                                                             I am confused totally - (boxley) - (4)
                                                                 Its the heap - (tuberculosis)
                                                                 You can't use the stack for a lot of things - (ben_tilly) - (2)
                                                                     Re: You can't use the stack for a lot of things - (deSitter) - (1)
                                                                         A good design is a good design... -NT - (ben_tilly)
                                                     Ah, I see... - (admin) - (3)
                                                         OK, OK,...Fair enough - (jb4) - (2)
                                                             The world is full of less-than-adequate programmers - (tuberculosis) - (1)
                                                                 And plain ol' automation is the mechanism - (FuManChu)
                                                     Don't get it. - (Arkadiy) - (7)
                                                         Circular references and Class GC - (tuberculosis) - (6)
                                                             Still don't get it... - (Arkadiy) - (5)
                                                                 I guess now I do - (Arkadiy) - (4)
                                                                     Think singleton - (tuberculosis) - (3)
                                                                         Translate into non comp-sci jargon? -NT - (deSitter) - (2)
                                                                             Singleton is a pattern - (tuberculosis)
                                                                             Translation - (ben_tilly)
                                                     This was a problem in Java 1.02 as well - (tuberculosis) - (4)
                                                         Re: This was a problem in Java 1.02 as well - (dshellman) - (3)
                                                             Could you elaborate on classloader problem? - (Arkadiy) - (2)
                                                                 Re: Could you elaborate on classloader problem? - (dshellman) - (1)
                                                                     As the article says, - (Arkadiy)
                                         what does Guitar Center have to do with this? :) -NT - (Steve Lowe) - (2)
                                             Re: what does Guitar Center have to do with this? :) - (deSitter) - (1)
                                                 Yes, and in the hands of a Master - (jb4)
                                         Java has gonorrhea? Or Java == gonorrhea? I'd buy either. -NT - (mmoffitt)
         I question the source - (ben_tilly) - (1)
             Agree - marketing angle is obvious - (tuberculosis)

Best thing since sliced SPAM!
150 ms