4

Background:

I have created an API and I did profiling for memory usage & process time for each web service using this guide and memory profiler gem.

I created a table to keep all profiling results like this:

      Request      | Memory Usage(b) | Retained Memory(b) | Runtime(seconds)
----------------------------------------------------------------------------
  Post Login       | 444318          |   35649            | 1.254
  Post Register    | 232071          |   32673            | 0.611
  Get 10 Users     | 11947286        |   2670333          | 3.456
  Get User By ID   | 834953          |   131300           | 0.834

Note: all numbers are the average number of calling the same service 3 consecutive times.

And I read many guides and answers(like this and this) says that Garbage Collector is responsible for releasing memory and we should not explicitly interfere in memory management.

Then I just forced the Garbage Collector to start after each action (for test purpose) by adding the following filter in APIController:

after_action :dispose

def dispose
   GC.start
end

And I found that Memory usage is reduced too much (more than 70%), retained memory almost same before and runtime is reduced as well.

      Request      | Memory Usage(b) | Retained Memory(b) | Runtime(seconds)
----------------------------------------------------------------------------
  Post Login       | 38636           |   34628            | 1.023
  Post Register    | 37746           |   31522            | 0.583
  Get 10 Users     | 2673040         |   2669032          | 2.254
  Get User By ID   | 132281          |   128913           | 0.782

Questions:

  1. Is it good practice to add such filter and what are the side effects?
  2. I thought that runtime will be more than before, but it seems less, what can be the reason?

Update:

I'm using Ruby 2.3.0 and I've used gc_tracer gem to monitor heap status because I'm afraid to have old garbage collection issues highlighted in Ruby 2.0 & 2.1

The issue is that the Ruby GC is triggered on total number of objects, and not total amount of used memory

Then to do a stress test, I run the following:

while true
  "a" * (1024 ** 2)
end

and result is that memory usage does not exceed the following limits (it was exceeding before and GC wont be triggered):

RUBY_GC_MALLOC_LIMIT_MAX
RUBY_GC_OLDMALLOC_LIMIT_MAX

So now I'm pretty sure that same GC issues of 2.0 & 2.1 don't exist anymore in 2.3, but still getting the following positive results by adding above mentioned filter (after_action :dispose):

  • Heap memory enhanced by 5% to 10% (check this related question)
  • General execution time enhanced by 20% to 40% (test done using third party tool Postman which consumes my API)

I'm still looking for answers to my two questions above.

Any feedback would be greatly appreciated

Moamen Naanou
  • 1,683
  • 1
  • 21
  • 45

0 Answers0