Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Extreme memory usage during rendering #823

Open
shivabhusal opened this issue Nov 30, 2018 · 2 comments
Open

[BUG] Extreme memory usage during rendering #823

shivabhusal opened this issue Nov 30, 2018 · 2 comments

Comments

@shivabhusal
Copy link

shivabhusal commented Nov 30, 2018

The following slim partial used 38GB RAM in Mac and 8GB in linux.

.drivers-view
  h2.title Drivers
  .actions
    //= link_to 'Add New Driver', new_driver_path, class: 'button'
    button.add onclick="window.location.href='/drivers/new'"
      ' Add new driver
    button#saveDriverButton disabled="true"
      '  Save

  - if @drivers.empty?
    p Your organization has no drivers.
  - else
    .table-box
      .table-scroll
        table
          thead
            tr
              th.text-center width="50" ID
              th Name
              th Image
              th Phone
              th OTP
              th Preferred base
              th Available time
              th Available days
              th Status
              th.text-center width="80" Actions
          tbody
            - @drivers.each do |driver|
              tr
                td
                  = driver.id
                td
                  = driver.name
                td
                  .driver-image
                    = image_tag driver.avatar.url(:medium), alt:( (driver.name) ? driver.name[0..1] : 'N/A')
                td
                  = driver.phone
                td
                  = driver.otp
                td.preferred-hub
                  = select_tag 'preferred_hub',  options_from_collection_for_select(::Base.sorted, 'id', 'name', driver.preferred_base_id.try(:to_s)),
                              class: 'custom-select', data: {worker_id: driver.id},
                              prompt: 'Select a Hub'
                  //i.fas.fa-angle-down
                td
                  = driver.time_available
                td
                  = driver.days_available
                td
                  - if driver.status
                    .label class=driver.status
                      = driver.status.humanize
                td.text-center
                  = link_to edit_driver_path(driver)
                    i.fas.fa-pencil-alt
                  = link_to generate_otp_driver_path(driver), class: 'margin15left', title: 'Regenerate OTP', method: :put do
                    i.fa.fa-sync

Problem

                  = if driver.status
                    .label class=driver.status
                      = driver.status.humanize

Solution

                 - if driver.status
                    .label class=driver.status
                      = driver.status.humanize

I have used = instead of - before if.

Conclusion

Its fixed now, but I expect SLIM to handle this

@deepj
Copy link

deepj commented Dec 3, 2018

I can confirm some performance issues as well. But they are not caused by = if and I could haven't figured out yet why.

@nbdavies
Copy link

nbdavies commented Dec 2, 2020

I've run into what I think is another manifestation of the same problem...

Let's say you have a helper method defined:

def link_to_yielded_url(link_text)
  url = yield
  link_to(link_text, url)
end

(With or without a &block argument.)
Then the usage might look like:

= link_to_yielded_url("Login")
  - if locale == 'es-ES'
    = login_url(country: 'es')
  - else
    = login_url(country: 'fr')

(The specifics here are made up.)

This kind of helper leaks memory, and if you use it inside of an each block, dozens or thousands of times, it starts to cause the kind of out-of-control memory consumption that @shivabhusal described.

If the nested block doesn't render (using =), then this memory issue doesn't occur:

= link_to_yielded_url("Login")
  - if locale == 'es-ES'
    - login_url(country: 'es')
  - else
    - login_url(country: 'fr')

The block still gets evaluated when yield is called. Using capture in the method also prevents the issue:

def link_to_yielded_url(link_text, &block)
  url = capture(&block)
  link_to(link_text, url)
end

This works correctly and safely whether you use - or = in the slim contents of &block.

So I guess this is ultimately a syntactic nuance, but the impact of it on memory consumption could be subtle and hard to pin down, or in the wrong circumstances, it could grind everything to a halt. Since memory consumption is the only observable difference in the result, it would be better if this could be handled safely by default.

@slim-template slim-template deleted a comment from Sod-Almighty Oct 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants