13

https://developer.gnome.org/glib/unstable/glib-GVariant.html#g-variant-ref-sink

I have read the above glib manual which says: "GVariant uses a floating reference count system. All functions with names starting with g_variant_new_ return floating references." But where is the actual description of what a floating reference count is? I couldn't find a comprehensive description of it.

In particular I want to understand when there is a need to unreference a variant and when not to. For example:

GVariant *a_v = g_variant_new_boolean(TRUE);
GVariant *another_v = g_variant_new("v", a_v);
  1. I think I don't need to unreference a_v because it is consumed by the second g_variant_new. Is that correct?
  2. Do I need to unreference another_v (assuming another_v is not passed to anything else from that point on)?
  3. Where is this documented? (I think I have the right understanding by inferring from different examples found during search but can't seem to find the official glib documentation that explains this clearly).
gpoo
  • 8,408
  • 3
  • 38
  • 53
kaylum
  • 13,833
  • 2
  • 22
  • 31

3 Answers3

11

There is a section on floating references in the GObject reference manual which goes into a bit more detail. Floating references may seem a bit obscure, but they are really very useful for C so taking a few minutes to really understand them is a good idea.

I'm going to assume you understand how reference counting work—if not there is a lot of documentation out there, take a few minutes and read up on that first.

First, lets look at what would happen with your example if g_variant_new_boolean returned a regular reference. When you first get the value, the reference count would be 1. When you pass it to g_variant_new, g_variant_new will increase the reference count to 2. At some point I assume you'll dispose of another_v, at which point the reference count for a_v will drop to 1… but remember, the memory isn't released until the reference count reaches 0.

In order to get around this you have two options. The first is to make g_variant_new steal the caller's reference, which basically sucks as a solution. You give away your reference when you call g_variant_new (or any similar function), so in the future you need to manually ref a_v every time you want to pass it to something else.

The other option is to just unref it manually when you're done. It's not the end of the world, but it's easy to forget to do or get wrong (like by forgetting to unref it in an error path).

What GVariant does instead is return a "floating" ref. The easiest way to think of it (IMHO) is that the first time g_variant_ref gets called it doesn't really do anything—it just "sinks" the floating ref. The reference count goes from 1 to 1. Subsequent calls to g_variant_ref, however, will increase the reference count.

Now lets look at what actually happens with your example. g_variant_new_boolean returns a floating reference. You then pass it to g_variant_new, which calls g_variant_ref, which sinks the floating reference. The reference count is now 1, and when another_v's refcount reaches 0 a_v's refcount will be decremented, in this case reaching 0 and everything will be freed. No need for you to call g_variant_unref.

The cool part about floating references, though, is what happens with something like this:

GVariant *a_v = g_variant_new_boolean(TRUE);
GVariant *another_v = g_variant_new("v", a_v);
GVariant *yet_another_v = g_variant_new("v", a_v);

When g_variant_new is called the second time a_v's refcount will increment again (to 2). No need to call g_variant_ref before passing a_v to g_variant_new a second time—the first call looks just like the first, and consistency is a very nice feature in an API.

At this point it's probably obvious, but yes, you do need to call g_variant_unref on another_v (and, in that last example, yet_another_v).

nemequ
  • 16,623
  • 1
  • 43
  • 62
  • Could you please explain this "and when another_v's refcount reaches 0 a_v's refcount will be decremented". When will another_v's refcount reach 0? – xXx_CodeMonkey_xXx Jan 18 '17 at 20:33
  • Whenever some other code calls `g_variant_unref(another_v)`. Basically, when the container (`another_v`) is destroyed it will decrement `a_v`'s reference count as well. Since that refcount is 1 before the call, decrementing it will reduce it to 0, which means it will be freed. Re-reading the 3rd paragraph (which describes what happens for **non**-floating references) might be helpful. – nemequ Feb 12 '17 at 03:15
  • I still don't understand where the floating GVariant object is deleted. In Cocoa we have the autorelease pool and that gets drained either manually or at the next time the code hits the event loop. And floating references look a lot like oversimplified autorelease pools to me. But i can't find any answer to it. – Lothar Feb 06 '23 at 00:07
0

The reference counting system is explained in the manual of GObject, in particular, in the section Object Memory Management.

When to use it might depend on your application (how the ownership of the variables will work).

The idea is similar to the way i-node works in Unix/Linux when handling files. A file is an object, located in a specific block in the storage. Whenever you create symlink to that file, the file is owned by one extra file (the reference counting increases). Whenever you remove a symlink, the reference counting decreases. When there is nothing owning the object, then it can be destroyed (or the space can be given back to the system).

If you destroy an object, and nothing is linking that object, you cannot use it anymore. If your object might have multiple owners, then you might want to use reference counting, so when one of these owners remove a counter, the object does not get destroyed... no until the last of the owners destroy it.

gpoo
  • 8,408
  • 3
  • 38
  • 53
  • Thanks for the pointer and explanation. But both seem to be about "full" reference counting. I understand that aspect of reference counts. What I don't fully understand is specifically "floating" reference counts. Just to illustrate that there is the concept of full vs floating ref counts, from the glib manual: "Calling g_variant_ref_sink() on a GVariant with a floating reference will convert the floating reference into a full reference." – kaylum Apr 16 '15 at 00:10
  • Indeed, they are about full reference counting. I did get wrong your question :-) – gpoo Apr 16 '15 at 07:14
0

There is a section on floating references in the GObject reference manual which goes into a bit more detail. Floating references may seem a bit obscure, but they are really very useful for C so taking a few minutes to really understand them is a good idea.

I'm going to assume you understand how reference counting work—if not there is a lot of documentation out there, take a few minutes and read up on that first.

First, lets look at what would happen with your example if g_variant_new_boolean returned a regular reference. When you first get the value, the reference count would be 1. When you pass it to g_variant_new, g_variant_new will increase the reference count to 2. At some point I assume you'll dispose of another_v, at which point the reference count for a_v will drop to 1… but remember, the memory isn't released until the reference count reaches 0.

In order to get around this you have two options. The first is to make g_variant_new steal the caller's reference, which basically sucks as a solution. You give away your reference when you call g_variant_new (or any similar function), so in the future you need to manually ref a_v every time you want to pass it to something else.

The other option is to just unref it manually when you're done. It's not the end of the world, but it's easy to forget to do or get wrong (like by forgetting to unref it in an error path).

What GVariant does instead is return a "floating" ref. The easiest way to think of it (IMHO) is that the first time g_variant_ref gets called it doesn't really do anything—it just "sinks" the floating ref. The reference count goes from 1 to 1. Subsequent calls to g_variant_ref, however, will increase the reference count.

Now lets look at what actually happens with your example. g_variant_new_boolean returns a floating reference. You then pass it to g_variant_new, which calls g_variant_ref, which sinks the floating reference. The reference count is now 1, and when another_v's refcount reaches 0 a_v's refcount will be decremented, in this case reaching 0 and everything will be freed. No need for you to call g_variant_unref.

The cool part about floating references, though, is what happens with something like this:

GVariant *a_v = g_variant_new_boolean(TRUE);
GVariant *another_v = g_variant_new("v", a_v);
GVariant *yet_another_v = g_variant_new("v", a_v);

When g_variant_new is called the second time a_v's refcount will increment again (to 2). No need to call g_variant_ref before passing a_v to g_variant_new a second time—the first call looks just like the first, and consistency is a very nice feature in an API.

At this point it's probably obvious, but yes, you do need to call g_variant_unref on another_v (and, in that last example, yet_another_v).

Stefano Sansone
  • 2,377
  • 7
  • 20
  • 39