Accessing Objects Memory Address in Ruby

Ruby, how to fetch origin object by its memory address or by object_id?

I do not know a way to "get" the Object by memory address (i.e. your 0x007f6f2b587b30),

but you can "get" the Object by object_id using ObjectSpace._id2ref(OBJECT_ID):

Solution:

Important: this still has inherit issues: see my recommendations below why.

app/controllers/gyms_controller.rb:

class GymsController < ApplicationController
@@gyms = Array.new
def private_page
...
gym = @page
@@gyms << gym
cookies.permanent[:gyms_object_ids] = gym.object_id
end
end

your view file:

- content_for :title, "History"
- breadcrumb :history
= stylesheet_link_tag 'application'

.outer
main.privacy-index
.content-wrapper
h1.headline2 History一覧
- cookies.permanent[:gyms_object_ids]).reverse.each do |gym_object_id|
- gym = ObjectSpace._id2ref(gym_object_id.to_i)
= gym.title
= gym.images
br

Recommendations:

  • use "class instance-variable" @gyms instead of "class class-variable" @@gyms. See why here.

  • if your @page variable above in your controller, is not a record (being that it does not correspond to any of the models you have, and thus is not saved in the DB), then create a model for it, so that you can save it into the DB, and retrieve these data in your views above through the model's record id, and therefore no longer by object_id.

    This would allow you to solve the following issues of my Solution
    above:

    • Objects reside in memory, and are subject to garbage collection. Therefore using ObjectSpace._id2ref(OBJECT_ID) is probably gonna fail at times if the Object is already garbage-collected. (see this SO), because ObjectSpace._id2ref above in my solution code runs at different code of execution than where the object is originally defined:

      • one is in the controller where @page object is defined (some request1 / say thread1),
      • the other one is in the view file where ObjectSpace._id2ref() tries to get that object (some request2 / say thread2),
    • in your code, you are using @@gyms = Array.new, which means that @@gyms (being stored in-memory) is not gonna be accessible to other rails processes because memory is not shared between these processes, and to put simply means that @@gyms would have DIFFERENT! values for each of the following processes:

      • rails server #1 (say... unicorn-1 in server1)
      • rails server #2 (say... unicorn-2 in server1)
      • rails server #3 (say... unicorn-3 in server2)
      • background worker process #1 (say... sidekiq-1)
      • background worker process #2 (say... sidekiq-2)
      • etc...

      ...whereas if you instead save the gyms (if possible and if necessary only) into a model and that these gym records belong to a user, then I would imagine doing something like below instead (which will solve these potential differing values above, and will no longer require you to use cookies):

      class Gym < ApplicationRecord
      has_many :gyms_users
      has_many :users, through: :gyms_users
      end

      class GymsUser < ApplicationRecord
      belongs_to :gym
      belongs_to :user
      validates :user, uniqueness: { scope: :gym }
      end

      class User < ApplicationRecord
      has_many :gyms_users
      has_many :gyms, through: :gyms_users
      end

How to print the memory location of a Ruby object

I don't know why would you want such a feature, and this is very implementation-specific, but on MRI 1.9 you can (ab)use object_id:

ruby-1.9.2-p180 :022 > class A; end
=> nil
ruby-1.9.2-p180 :023 > a = A.new
=> #<A:0xa2b72e4>
ruby-1.9.2-p180 :024 > a.object_id.to_s(16)
=> "515b972"
ruby-1.9.2-p180 :025 > (a.object_id << 1).to_s(16)
=> "a2b72e4"

For an explanation of why does it work, check out the relevant lines in MRI gc.c.

Note that this will not work on other implementations (JRuby, Rubinius), and may very well break in future versions of Ruby. Also, there may be no way at all to get the address in some implementations (I suspect that you cannot in JRuby; I'm not sure, through).

Object address in Ruby

You can get the address using object_id and multiplying it by 2* and display it in hex using sprintf (aka %):

"#<Thing:0x%08x>" % (object_id * 2)

Of course, as long as you only need the number to be unique and don't care that it's the actual address, you can just leave out the * 2.

* For reasons that you don't need to understand (meaning: I don't understand them), object_id returns half the object's memory address, so you need to multiply by 2 to get the actual address.

ruby : can't understand memory address

You might be confused specifically because you're using integers. Integers in Ruby are singletons: their integer value determines their object id.

x = 3
y = 3
x.object_id == y.object_id # true
x = "a"
y = "a"
x.object_id == y.object_id # false

However this is only true for integers up to a certain size.

x = 11111111111111111111111111111111
y = 11111111111111111111111111111111
x.object_id == y.object_id # false

This is because Ruby actually stores the integer value in the object id if it is small enough. If the number is too big it has to allocate a new object.

Print memory address for Ruby array

Use the method Object#object_id.

Returns an integer identifier for obj. The same number will be returned on all calls to id for a given object, and no two active objects will share an id. #object_id is a different concept from the :name notation, which returns the symbol id of name.

Example :-

Arup-iMac:arup_ruby $ irb
2.1.2 :001 > s = "I am a string"
=> "I am a string"
2.1.2 :002 > obj_id = s.object_id
=> 2156122060
2.1.2 :003 > ObjectSpace._id2ref obj_id
=> "I am a string"
2.1.2 :004 >

Rails convert memory address to object

I think you should pass an object_id instead of whole object to your worker.

Call worker:

NotifySubscriberWorker.perform_async(@incident.id)

Then change in your worker:

SubscriberMailer.notify_subscriber(subscriber, incident_id)

and then in mailer:

  def notify_subscriber(subscriber, incident_id)
@incident = Incident.find(incident_id)
mail to: subscriber.email, subject: "There is an update to #{@@app_name}'s status.'"
end


Related Topics



Leave a reply



Submit