We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

New Ruby 2.1 Awesomeness: Fine-grained Object Allocation Tracing

00:00

Formal Metadata

Title
New Ruby 2.1 Awesomeness: Fine-grained Object Allocation Tracing
Title of Series
Number of Parts
50
Author
License
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language
Producer
Production PlaceMiami Beach, Florida

Content Metadata

Subject Area
Genre
Abstract
Ruby 2.1 is coming out soon with an amazing new feature under ObjectSpace: #trace_object_allocations. We are now able to trace the file and line number (as well as method) where any Ruby object is allocated from. This is a very welcome feature, as object-level tracing has been very difficult in Ruby, especially since the memprof gem could not support Ruby past 1.8.x. This new Ruby 2.1 feature is really just exposing some raw (and vast) data, so it can be difficult to tease out meaningful information. Two gems are introduced in this talk to solve just that problem. The objspace-stats gem allows us to view and summarize new object allocations in meaningful ways. We'll look at how to filter, group, and sort new object allocations. The second gem is rack-objspace-stats. We'll see how this tool can intercept requests to a Rack stack, and measure new object allocations taking place during the request. (For those familiar, this works very similar to the rack-perftools_profiler gem.) We'll look at various examples of how this new Ruby 2.1 feature, and these tools can help an organization reduce unnecessary memory allocations, and speed up their code, especially mature Rack applications.
Memory managementObject-oriented programmingSpacetimeObject-oriented programmingCountingRead-only memoryReduction of orderSpeicherbereinigungStatisticsInstallation artSocial classSource codeCartesian coordinate systemMemory managementVirtual machineObject-oriented programmingCodeSocial classTracing (software)Semiconductor memoryString (computer science)Product (business)CuboidSystem callBlock (periodic table)InformationNumberStatisticsTerm (mathematics)SpacetimeBitComputer fileCountingLevel (video gaming)Library (computing)QuicksortUniform resource locatorSource codeDisk read-and-write head1 (number)MathematicsFunction (mathematics)Line (geometry)Contrast (vision)Network topologyMathematical modelProfil (magazine)IterationCycle (graph theory)Multiplication signPoint (geometry)Order (biology)Hash functionInstance (computer science)Slide ruleSpeicherbereinigungInternetworkingPosition operatorBlogObject-oriented programmingMobile appMessage passingOnline helpInstallation artDot productReduction of orderGraph (mathematics)Module (mathematics)Variable (mathematics)
StatisticsSource codeString (computer science)Local GroupHash functionSocial classPunched cardScalar fieldMaxima and minimaConditional-access moduleStrutDreizehnMaizeThomas KuhnPrice indexTrailMIDIObject-oriented programmingSpeicherbereinigungMemory managementConvex hullSummierbarkeitHill differential equationRemote Access ServiceMenu (computing)User interfaceExecution unitDirectory serviceSimulationMultiplication signSocial classString (computer science)Network topologyLine (geometry)SequenceProgramming languageResultantInstance (computer science)Matching (graph theory)Electronic mailing listGroup actionSpherical capObject-oriented programmingDefault (computer science)Memory managementLibrary (computing)AliasingStructural loadDifferent (Kate Ryan album)Function (mathematics)QuicksortProcess (computing)Hash functionRemote Access ServiceComputer fileComputer configurationNumberDot productRoutingBlock (periodic table)Table (information)SpeicherbereinigungCodeMehrplatzsystemRight angleDependent and independent variablesMobile appStatisticsSource codeView (database)Regulärer Ausdruck <Textverarbeitung>MiddlewareKernel (computing)CausalityCountingSubsetArray data structureOnline helpSystem callParameter (computer programming)Directory serviceTrailTemplate (C++)Game controllerGraphics tabletBit rateCore dumpCartesian coordinate systemRule of inferenceDirection (geometry)DialectWebsiteWave packetDatabaseBitInformation
Memory managementNormed vector spaceVariable (mathematics)String (computer science)Multiplication signKey (cryptography)Mobile appCartesian coordinate systemElectronic mailing listFunction (mathematics)QuicksortNumberInteractive televisionComputer fileGroup actionMemory managementObject-oriented programmingLine (geometry)SummierbarkeitRemote Access Service
WindowBookmark (World Wide Web)MathematicsRemote Access ServiceMemory managementMotion blurString (computer science)GoogolView (database)Computer-assisted translationMobile appAliasingCausalityComputer fileRemote Access ServiceFunction (mathematics)Computer animation
String (computer science)CalculusLocal GroupGroup actionStatisticsMemory managementProxy serverCommunications protocolProgrammable read-only memoryFatou-MengeSummierbarkeitObservational studyConvex hullDefault (computer science)Line (geometry)Group actionSocial classGraph coloringInteractive televisionObject-oriented programmingCodeWeb pageProcess (computing)1 (number)Memory managementElectronic mailing listScripting languageCartesian coordinate systemComputer fileCombinational logicComputer animation
Price indexIntegerLink (knot theory)Mach's principleInfinityDynamic random-access memoryExecution unitMeta elementMemory managementSummierbarkeitInformation managementJava appletRight angleMultiplication signField (computer science)Mathematical optimizationString (computer science)DatabaseKey (cryptography)CodeMetaprogrammierungMemory managementTheory of relativityLink (knot theory)Game controllerLine (geometry)State observerObject-oriented programmingProjective planeTemplate (C++)Row (database)Task (computing)Content (media)Existential quantificationStatement (computer science)Java appletView (database)CASE <Informatik>BuildingHand fanWeb pageProcess (computing)Mathematical modelSpeicherbereinigungComputer programmingSystem callContext awarenessResultant
Finitary relationVariable (mathematics)Core dumpImage warpingGroup actionCAN busAxiomComputer configurationFunction (mathematics)Line (geometry)Memory managementSpeicherbereinigungSpacetimeGoogolBlogImplementationFunctional (mathematics)Mobile appComputer programmingSoftware testingVariable (mathematics)Server (computing)Multiplication signStatisticsMemory managementBuffer solutionCore dumpObject-oriented programmingDifferent (Kate Ryan album)Form (programming)InternetworkingRow (database)BuildingAttribute grammarBoiling pointBlogCodeSystem callPoisson-KlammerLine (geometry)SpacetimeInterpolationString (computer science)Link (knot theory)View (database)Revision controlFunction (mathematics)Hash functionInstance (computer science)Inheritance (object-oriented programming)Open setSlide ruleCognitionReading (process)SpeicherbereinigungSocial classComputer fileVideoconferencingGame controllerMathematical modelData miningCentralizer and normalizerLogical constantClosed setSymbol tableRight angleSingle-precision floating-point formatTable (information)Goodness of fitCellular automatonStatement (computer science)ChainMereologyTheory of relativityExtension (kinesiology)Tracing (software)Cartesian coordinate systemDatabasePatch (Unix)Set (mathematics)WeightCuboidSequelPoint (geometry)Ring (mathematics)Noise (electronics)Video gameHand fanProcess (computing)Speech synthesisDependent and independent variablesInterpreter (computing)Wave packet
SoftwareVideoconferencingScalable Coherent InterfaceEvent horizonComputer animation
Transcript: English(auto-generated)
Thanks everybody for staying for a late afternoon talk.
So I'm gonna talk today on Ruby 2.1, a new feature in Ruby 2.1 called It's All About, It's About Tracing Object Allocations. My name is Sam Rollins, and on the internet I'm S. Rollins. The slides are on my GitHub if you look at GitHub's Rollins. So Ruby 2.1 0 preview one is out.
This is exciting. You can grab it with RBM. You can grab it with RVM. This is the Ruby 2.1 news file. If anybody saw Koichi's talk, he, he stole this from me. This is actually, I stole it from earlier talks of his where he does this, and the gag is that this is much smaller than the news file for 2.0.
So the feature that I'm gonna talk about is way in the corner there. It's object space dot trace object allocations. So object space isn't new. This module has been around. People may have used it for things like count objects or each object. What's new in 2.1 is the object space dot
trace object allocations method and then some sibling methods. You have trace object allocations start, stop, clear, and a few others that they're, like, each day when you check the changelog they've added a few more. So the ones in Asterix are not available yet. They will be available in 2.1 0 preview two. I was hoping that would be released by RubyConf and it has not. So you can't get
it with Ruby 2.1 0 preview one. You'll have to get ahead and I'll, I'll show that later. So let's start out with an anecdote from GitHub. They have a blog post called Hey Judy Don't Make It Bad that kind of details this. So they looked and they saw, when they fire up the GitHub application and immediately count
how many objects it has, just right after firing it up, it has more than six hundred thousand objects. And they thought this is crazy and unexpected. Why is this? So they wanted to explore why this happens. Where am I supposedly hogging all this memory? Where am I, where, what Ruby files and what classes are allocating all this memory?
So this was a really hard problem to solve until Ruby, this new feature in Ruby 2.1 0, trace object allocations. We have lots of CPU profilers and other various tools, SQL profilers. But until this tool, this, that was a really hard question to answer. So let's look at an example. Hopefully there's enough
contrast and we can, we can read this. So I, I have a class called myclass. It has two methods. An array returns an array. So therefore it allocates an array and returns it. And then a string returns a string after allocating it. So let's look at an example of how we can trace that code. So what we
can do is we have some code that we want to trace. It's allocating memory and we want to see where. So that's gonna be the two lines in the middle there. A equals myclass new an array. So we're saving that array variable. And myclass new a string. We save that to s. And we want to trace this. So to trace it, you wrap your code in
a block and pass it to trace object allocations. And then afterwards you have these methods available to you. You can call object space dot allocation source file and pass it in your object. And that's gonna give you back example dot rb, the file that it was, that it came from. And you can say allocation source line. That tells you line three. So back up there,
the return with the array is on line three. You can also ask for the class path and the method id that allocated your object. So another way to invoke this, if you, if it's maybe a little bit kludgy or hard to wrap the code that you want to trace in a block, you can instead call trace
object allocation start and then run the code that you want to trace, and then call trace object allocation stop. That is, again, not available in preview one. That's in trunk. So why are we doing this? Why is this a useful feature? In general, you, many, many product companies are in the position where they
want to reduce their memory footprint. You have a large, maybe a Rails app that's using a lot of memory, and you want to reduce that. I think more commonly, or, yeah, more commonly, people want to reduce garbage collection time. So this is, of course, a, like, theme for the conference. Each iteration of Ruby has an improved garbage
collector. If you, if you do profiling for a large Rails app, you might see that you're spending some large amount of time in garbage collection. So if you can manage to allocate fewer objects, then you're gonna reduce time in marking objects and in sweeping those objects. If you were
in on Koichi's talk, he, he mentioned that, especially in Ruby, he, he showed an excellent graph. Most objects are, are young objects, so they are created, and then on the next garbage collection cycle, they're pronounced dead and they're collected. And then more objects are created and they're, and they die. So if you can reduce, somehow, if there are
accidental allocations of young objects, if you can reduce that, you can really improve garbage collection time in your app. You say, well, my Ruby, my application isn't on Ruby 2.1. Like, I don't, I don't think it's compatible. If your Ruby application is running on Ruby 2, it should be compatible. I think there are very few incompatibilities, and what you can do
is, if you can get, just on your one machine, if you can get your application running on 2.1, then you can use the trace object allocations feature as a diagnostics tool, and you don't have to go through the whole production whatever to get your production app on 2.1. If you want to just use this locally on your box.
So that feature seemed neat, but it's pretty, it was pretty limited. I had to have a handle on an object and say, hey Ruby, what file allocated this? And what line number? And you have to, like, have your hands on these objects, if you want to ask about, if you want to find out where they were allocated. And it's really fine-grained. It's, it's telling us information about
each single allocation. So this isn't terribly useful without some more, some more work ahead of us. So it's just the start. This feature allows us to write better tooling on top of Ruby that can help us find where we're allocating objects. So the next step is gonna be aggregation. You
want to be able to aggregate these statistics, these, this information about your allocations, and find what, what are the worst offenders in terms of files or classes that are allocating objects. So we've, I've got a gem out, allocation stats, that is gonna help us do this. Unfortunately, it requires at least
an unreleased Ruby 2 1 0 preview 2. Hopefully, I honestly think within the week, Koichi said in a few days they want to release preview 2. For now, you can still install Ruby trunk with rbn or rvm. They both have commands available for you to do that. So let's look at a low level example of how
this library's gonna work. We again have a class and a method inside that class, and the method on line three is gonna create a hash, and on line four it's gonna create a string. So we can require the allocation stats gem, and then the code that we want to trace is gonna be there on line ten. My class dot new dot my method. We want to run this
code and see, see where allocations happened. So you take that, you wrap it in a block, pass it to allocation stats dot trace, and you'll get back an object. So you get back, you get back this allocation stats object, and you can call allocations dot to text on it to get you this tabular output. Oh, and it doesn't show too well. All right. So what it's showing us
there is that, let's look. On line four of trace my class raw dot rb, we have allocated a string. And you can see the, the class path and the method id that allocated it are my class and my method. It also shows you on line three we allocated, it's cut off at the end, we allocated a
hash and three strings. So those were all on line three, and you see the three strings are the value, the value, three values for the hash. And on line ten we allocated an instance of my class. So my class dot new is what allocated that. That's not powerful enough yet. We're still just looking
at a tabular output of individual allocations. So let's try and group our allocations. We have the same code up at the top. Same code all the way down through line eleven. We're gonna trace a call to my class dot new dot my method. This time, though, we're gonna call allocations dot group by. We're gonna pass in, we, we wanna group by the file, the line number, and the
class of the object being allocated. So we're gonna create groups of these and output that to a tabular output again. And this time we have something more useful. We can see that we allocated three strings on line three of the file. We allocated one hash on line three, one more string on line four, and one instance of my class
on line ten. Let's look at a more complicated example. We can, we can look at where the psych library allocates. So this is the built in YAML library in Ruby. So let's do the simplest thing we can think of when we want to generate a YAML string. Almost the simplest. We're gonna
take an array of two strings, and I want to convert that to YAML. It seems like a pretty trivial example. So here we're gonna call allocations. We're gonna pass an alias paths true, and I'll show you what that does. And we, I'm gonna group by the source file and the class of the object and get us some tabular output. So here
we see, at the top there, there were thirty-eight instances of a string being allocated in visitor dot rb. And we also see five instances of a match data, so a result from a regular expression execution, in visitor dot rb. And the, the all caps Ruby libdir on the left there,
that's the alias paths bit that's built in, so half the time your rbn or rvm class paths for these, for gems or Ruby libdir would, that wouldn't even fit on the slide itself. So to make it easier for everybody, we can alias paths. So Ruby lib files will be prefaced with Ruby
libdir and then there's gemdir and dot or anything in your current working directory. Let's sort those allocation count, let's sort those groups by how many were allocated in each group, so by the count column. So here we're gonna group by source file and class again. We're gonna sort by count this time for something more useful. And
now this is something that's getting much more, much more interesting, right. So now we have the top three offenders in YAML, in psych. We have thirty-eight strings being allocated on visitor. Again, this is just to convert an array with two strings into YAML. So this gets kind of interesting. You kind of want to go into visitor dot rb now
and see what's going on. There's twenty-one strings in YAML tree, twelve arrays in YAML tree, and on and on. So class plus is a feature I added as well. So for this example, we're gonna use the hike gem. So hike is kind of the core of sprockets. It allows you to take
a subdirectory somewhere, and you say, give, find me all the files that match this filter. So here we're gonna look at the hike direct, library tree itself, and find me all the, all the rb files that have hike in them. So pretty simple hike example. Here this time I'm gonna group by the source file and class plus, which will give
us some more information other than class. So here we see, if you look at the class plus column, it's, it's telling us that, in kernel require dot rb, there were a hundred and thirty-four allocations for an array, and for all of those allocations, the members were fixnum or false
class. So they were all integers or false. The next highlighted one down says that all the allocations in path name of an array for all of them, the members were strings. So that's pretty cool. What might seem a little weird about this list is that there are a ton of allocations here. Four hundred thirty-eight, one fifty-two. Why is this so expensive? And then
the directories are weird too. These are all, these all come from the Ruby gems directory, and it's kernel require dot rb, and we have some Ruby VM instruction sequences. So what's actually happening here is that the first time I use the hike library, that's when it loads all the, that's when Ruby loads all the files, or Ruby gems I guess, loads all the files,
and so the loading process is allocating strings left and right, Ruby VM instruction sequences. So this is not useful. We need to filter this out. So we've got another option, burn. So burn is like burning in poker. We can burn one when we trace a block of code. So what
burn one is gonna do is it's gonna run our block once without tracing anything, and throw away whatever happened. And then it's gonna run again while, with object allocation tracing turned on. So now we get much more useful results. So that was the same hike code. Now we see that all the allocations are happening in the hike gem or
in Ruby's path name dot rb. That seems to make more sense. So object churn is kind of the next subset of problems in, in expensive garbage collection. This is kind of the idea of, of young objects. One specific instance of this that hits a lot of us, I'm sure, is per Rack request allocations. So this
is where, for the sake of an example, let's say this is a Rails, we have a Rails app, and you have a request coming through. It's gonna have to go through all your Rack middleware, all your, the routes into a controller, action, your views, your helpers. It's generating, it's pulling out objects
from the database. It's generating lots and lots of objects. And as soon as a response has been generated, it's gonna throw away how much of that, like most of that, right. And so every single request, every single user that's hitting a Rack app like this is, is generating all these young objects and they're immediately being swept away on the next garbage collection.
So a great way to see how your Rack app is allocating objects is another gem I have called Rack allocation stats. So this is a Rack middleware. Let's say you have a Rack app sitting at my dot Rack dot app on port 9292 and you want to send, you have some view or resource sitting at slash path with parameters foo equals
bar. You can just append and ras trace equals true, and that will kick off Rack allocation stats. So ras there stands for Rack allocation stats. We'll see lots of ras parameters. So let's look at a simple Sinatra app. Hopefully we can see most of this. This
is very simple. At slash erb, all we're gonna do is we're gonna parse an erb template. It's sitting down here. All it does is it creates a list of hello world in, with hello in these six different languages. So here's that app. It's sitting at, we're looking at slash erb. When I take, and when I take question ras trace equals true onto
the end, I now have a tabular listing. It's sorted of all the allocations that are happening. So this is the, the default grouping is by file and line number and the class of the object. So you can see at the top there, we've got, I'm not gonna do it. We've got forty-six strings being allocated on
line four hundred and forty-five of erb dot rb. And so that's, that's your sorting. So there's lots of different options that ras accepts, and I'm adding a lot, cause I'm, I'm actively working on this. So ras help will give you a, will respond with a man page style help.
Alias paths equals true will, again, alias those paths at the front, so you can see at the top, erb's in Ruby libdir, a couple lines down, we are doing a lot of string allocations in, in gem colon sinatra one three three. Ras times is, will pass the request down into
your Rack app n number of times. So, for this it would be ten number of times. So if your application maybe has some variability in the path that it takes or the objects that it's allocating, you can do ten times and then you'll see like a sum of what happens, what happens over ten requests, where, where, where the big offenders in allocating objects.
You can also output to JSON, so there's a little snippet of some JSON. If you prettify it, it looks like this. So it's an array of groups. So you've got the group key there, we're grouping by that file, that line number, and string objects, and then you get a list of all the allocations that happen there. You can do fun things with that.
Output interact, output equals interactive is another fun way to, way to use this tool. So let's actually demo that. I can demo all of these. So here's my Rack app again. I'm gonna say ras trace equals true. OK, so now I
get, these are, this is the sorted list, you can't tell cause it's like the tiniest monitor. So I'm gonna and ras alias. Oh, it's already there. Paths equals true. Now it's a little more readable cause I've shortened my file names. If I instead go interactive, output equals interactive. Let's see
what we get. So it's mostly visible. It's, we get this JavaScript application, this interactive application, where we can kind of poke around and see where we're allocating objects. So right now, by default, it groups by file and line and class plus. I can take off line and say, OK, so this ERB file
is allocating a lot. Sinatra base dot rb. I can filter out Ruby and say I just want to look at gems. I'm interested in where the gems are allocating objects. And there's, most often there's a long tail of allocations. So here, most
of the page is filled with like, oh this file allocated one of these and one of these and two of these. Which is not terribly interesting to you, so you can shorten it and say, just show me the interesting ones. So now if I go one more, now we're looking at, this is a nice little compact list of all the, of all the offenders of all the combinations of file, line, and class that are using,
that are allocating more than, that kind of account for more than one percent of the allocations. So you might want to look in here and say, like, why is, first of all, why does it have fifteen hundred lines? And then why is base dot rb, why is that line allocating so much? Like, this was a pretty simple application. Maybe this can be reduced. So that's interactive. So you're saying, OK,
what do I do? You've shown me how to look at where my, my applications, my Ruby code is allocating objects. What, what do I do about that? Well, you want to allocate less. That's the goal here. How do I allocate less, you say? OK, that depends. This can be pretty tricky, actually. I think
a lot of times, this is, the, Koichi's observation is not terribly new. This is true in the Java world, when people do garbage collection, academic papers and such, they, they see that most objects are young objects. They die when they're young. So there's, there's maybe not a lot you can do, but let's see what we can do.
OK. If this is readable, the red might not be. This was a very simple pull request I sent to the temple gem, where on, on that, on that Sinatra app, if you use a slim template instead of ERB, the biggest offender is this line in temple, where they're saying keys plus equals
h dot keys. If anybody knows, let's say keys is an array. Plus equals is gonna allocate a new array. And the Ruby documentation is actually really good about this, so I have some links to the documentation there. Ruby's documentation says plus will allocate a new array and fill it with the contents of keys and h dot keys. So that's allocating
a new object right there. In this case, we don't need to allocate a new object. We can use the concat method instead, which will concatenate the second array onto the first array and reduce our allocations. Memoization is a good technique for reducing this. I'm, I'm not advocating premature optimizations. You should kind of
see where your offenders are and, and then see if you want to memoize those, those spots. So we'll look at some examples of these. A big one is string building, where you might be concatenating strings. You might be using some metaprogramming and building a method name that you're gonna just pass to send and then throw away the method name that you've just built up. So we can
look at a few examples of what we can fix there. Let's look at Rails 3.2.15. The latest Rails 3.2. So here I've got a very, very, very simple Rails app. It has two models. It has projects and tasks. And projects have many tasks. And on this page, we have a view with ten projects, and
each project has, I think it's four tasks. And, and we're displaying these various fields of them. So, theoretically, for this page, we are retrieving about one hundred stringy fields from the database. So that's like some context of what, what work maybe should have been done for this.
When I add ras trace equals true, and let's look at it interactively, we get these results. So we can see at the top here, active record relation allocated seven hundred and fifty-six strings. So that's pretty wild. It doesn't, I mean, I showed you it. Project has many tasks. That was the only
relation that we have here. I didn't do anything fancy in the controller. I literally, Rails knew, and then it created those two models, and we have this. So something's a little fishy here. We also have active support callbacks generating seven hundred and seven strings. And then the next one is SQLite three statement is generating a lot of strings. Only three hundred thirty-two strings, actually. And, and SQLite three is, is, is
where I'm pulling those supposed, you know, one hundred stringy fields out of the database. So this maybe isn't a huge offender. We're allocating three times as many strings as we were expecting. If you dig into the code, you know, it's possible that, that a lot of that's unavoidable. So let's look at some of these, some of
these big offenders. Active support callbacks dot rb. So here, any time you have a callback, I, I think this is active support, so this is gonna be for your callbacks in your models and callbacks in your controllers. It has to build the names for the callbacks, and it does this every single time so that it can send on line eighty-one there. And so this is crazy expensive.
Every single time you, you wanna call methods, you just wanna call your callbacks in a response, Rails is, is building these methods each time, as if it doesn't, as if it's never built them before, and as if, as if they're gonna change from time to time, right, these callback method names. So this is pretty ridiculous. Luckily in Rails 4,
this is all fixed. We, you can see now we are caching the, the callback runner names in a thread-safe cache, so that's pretty excellent. That'll reduce the allocations in, in a Rails 4 app. If we look at active record relation, this class was pretty wild. So it starts with these
three constants with lots of, with lots of symbols in them, and these symbols are basically going to be instance method, or instance variables. So as soon as we initialize a new active record relation, so like, if you're chaining relations or pulling things out of the database, you're initializing new relations. It takes each of these, and it's
gonna do instance variables set, and then build a string with what it wants to set, right, because it's, it's gonna append this value at the end and it's gonna put an app in front. And every single time you create a new active record relation, it's building this string and throwing it away for, like, thirty odd attributes that it's doing
this for. So this was pretty wild and inefficient, and this code has just been totally rewritten for Rails 4, so it, it doesn't apply anymore. But this was why that was such a huge offender in a Rails 3.2 app. It's not always easy to fix these things. So there are some, I think I, I think these links are actually to the Rails 4 version to show you that, like, there's some that still
exist and I'm not sure how they should be fixed. So if we look at active supports output safety, which is where you get HTML safe and some methods like that, we see that at the very end of the, the file, it puts this HTML safe method on string, and all, all that does is it creates a new safe buffer instance
passing in the string. And safe buffer inherits from string, so that immediately allocates a new string with that, because we're, we're creating a new one. And so this isn't, it's not terribly obvious how you could solve this. Any time you want to HTML safe something, the, you know, the idea, the active support idea is to create this new class, this safe buffer class, and put your string
in there. And so you can, you can theorize a bunch of different ways that this might be solved, but I don't think it's obvious how, there's no quick solution. I think that this maybe should be done with care if this is gonna be fixed. We have the tag helper here. This one's a big one. So any time you're using a
form helper in Rails, so, or, I'm sorry, a view helper, so form helpers, the JavaScript helper tags, all these, you know, link four, they all kind of boil down to a call to the tag method, which is going to have an open bracket and then a bunch of string interpolation with the things that are passed into it, and then it
has to decide whether to open or close, or to leave the tag open or close it. So over on the right you see it's either a write bracket or slash write bracket. So all of those are strings that every single time tag is called, those strings have to be allocated again. Every single time. And so this is again not, it's not easy how to solve
this. Like, all of your tags are gonna be different if you have some view with table with hundreds of cells in it or something, like, they're probably all different. It's, there's, memoizing's not a good idea here, right. This one's kind of tough. How, how we can, how we can reduce allocations in that one.
The SQLite three offense that we saw was, it happens right here on line one oh eight of statement dot rb, val equals step. So why is this allocating so many strings? It's, it doesn't appear to allocate any strings. It presumably calls this step method, so where is that? And you search for it in statement dot rb and it's not
there. And that's because it's a C function in statement dot C. So the SQLite gem is, is part C extension and part Ruby. So if you want to fix those string allocations, you have to now, like, know the C API for Ruby and go in and see which methods are allocating strings. So that's not impossible to fix, but it's a little, little more tricky to, to fix
that one. But in general, I think that we should be excited. I think that these are all really new, really exciting features to add to our, our performance tool chest. So we have a bunch of different gems out there already. This thing is, is new though. Provides new functionality. I think that it's important for us to be aware that Ruby
allocates objects. Because we have a garbage collector, it's hidden from us. Every Ruby implementation hides this from us, that we allocate objects, and we don't know that we're programming badly until our app is suddenly hundreds of megabytes and we have, like, all these unicorns on one server and each of them is three hundred meg and we've got just a mess on our hands.
So I think it's important to think about how, when you're, when you're appending, when you're chaining methods in a collection, so chaining hash methods or array methods or string methods, that you could be instantiating new objects and that you may not need to. Be aware of how much garbage collection costs you. So this one's kind of a fun test
to do. If you haven't used perftools.rb, or I think it's, is it rack perftools? There's, there's a rack gem. It is amazing to see, in a, in a big application, how frequently we're object, we're garbage collecting, and, and how much time it takes, especially in a Ruby one nine app.
So, I think that that's really important to be aware of that, and if you're having performance problems, there's a good chance that it's garbage collection. If you, if you cruise around the internet for people fixing their own Ruby performance problems, a lot of it is tuning the garbage collector. I think GitHub, Twitter, oh, there's another one. I think Airbnb
all have articles on how they've tuned the garbage collection, the garbage collector, for their own purposes. And I think it's important to add this, this tool to your toolbox. So watch this space. This tool is actually, the trace object allocations functionality is still being written. Aman Gupta committed something, I
think yesterday morning, to this, so like, it's changing every, I have to constantly rewrite my slides as I'm doing this. And, and I think also, so I've written a few gems that, that I just showed, but I think what this tool does is, what the, what the, the new Ruby functionality does, is it's going to allow us to build
really great tools and more tools around this. So I think we should be cognizant of that, of how we can, we can reduce our object allocations by using different tools. So things to Google if you're interested in this talk. First of all, now that I've been here a few days, a bunch of the talks here. So Koichi's talk, Pat Shaughnessy's talk was really excellent on
the garbage collector and different implementations. Koichi's previous talks. So, you should read GitHub's blog post, Hey Judy, Don't Make It Bad. This is a really interesting read. It actually, so it starts out telling the story that GitHub wanted to solve that problem of 600,000 objects. So they have a fork of Ruby. Aman
Gupta writes this feature into Ruby to see what files and lines are allocating objects. And they kind of find where the problem is. It's an interesting read. So then Aman opens up a feature request at Ruby core and Koichi adopts it into Ruby 2.1. So that's kind of the back story of how that feature got put in here.
You can search for the two gems, allocation stats and rack allocation stats. And I would definitely search for, especially if you saw Koichi Sasada's talk, I would definitely search for his other talks. I think it's called Building a More Efficient Ruby 2.1. So he gave one at Ruby Kaigi and one at Yuroku, and there should be videos of
both of those. And he changes his talk each time. So he kind of gave the same talk at, at RubyConf, but, you know, it evolves because he's writing these features. As a matter of fact, like, his talk yesterday had a bunch of features that I think he committed yesterday, or the day before. It was pretty goofy. And I need to thank Aman Gupta for writing
this initially, GitHub for everything that GitHub ever does. Matt Brooks is a coworker of mine who helped me with the slides. Ruby Central for putting on this incredible conference. And then Hakeem for reveal.js, which is what this talk is written in. And that's everything. So.