mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-28 10:30:03 +01:00
GVariant: Convert docs to markdown
Specifically, convert the sections to markdown syntax.
This commit is contained in:
parent
9b6cc973a0
commit
d8bbc77cb3
357
glib/gvariant.c
357
glib/gvariant.c
@ -91,201 +91,168 @@
|
||||
* values. #GVariant includes a printer for this language and a parser
|
||||
* with type inferencing.
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Memory Use</title>
|
||||
* <para>
|
||||
* #GVariant tries to be quite efficient with respect to memory use.
|
||||
* This section gives a rough idea of how much memory is used by the
|
||||
* current implementation. The information here is subject to change
|
||||
* in the future.
|
||||
* </para>
|
||||
* <para>
|
||||
* The memory allocated by #GVariant can be grouped into 4 broad
|
||||
* purposes: memory for serialised data, memory for the type
|
||||
* information cache, buffer management memory and memory for the
|
||||
* #GVariant structure itself.
|
||||
* </para>
|
||||
* <refsect3 id="gvariant-serialised-data-memory">
|
||||
* <title>Serialised Data Memory</title>
|
||||
* <para>
|
||||
* This is the memory that is used for storing GVariant data in
|
||||
* serialised form. This is what would be sent over the network or
|
||||
* what would end up on disk.
|
||||
* </para>
|
||||
* <para>
|
||||
* The amount of memory required to store a boolean is 1 byte. 16,
|
||||
* 32 and 64 bit integers and double precision floating point numbers
|
||||
* use their "natural" size. Strings (including object path and
|
||||
* signature strings) are stored with a nul terminator, and as such
|
||||
* use the length of the string plus 1 byte.
|
||||
* </para>
|
||||
* <para>
|
||||
* Maybe types use no space at all to represent the null value and
|
||||
* use the same amount of space (sometimes plus one byte) as the
|
||||
* equivalent non-maybe-typed value to represent the non-null case.
|
||||
* </para>
|
||||
* <para>
|
||||
* Arrays use the amount of space required to store each of their
|
||||
* members, concatenated. Additionally, if the items stored in an
|
||||
* array are not of a fixed-size (ie: strings, other arrays, etc)
|
||||
* then an additional framing offset is stored for each item. The
|
||||
* size of this offset is either 1, 2 or 4 bytes depending on the
|
||||
* overall size of the container. Additionally, extra padding bytes
|
||||
* are added as required for alignment of child values.
|
||||
* </para>
|
||||
* <para>
|
||||
* Tuples (including dictionary entries) use the amount of space
|
||||
* required to store each of their members, concatenated, plus one
|
||||
* framing offset (as per arrays) for each non-fixed-sized item in
|
||||
* the tuple, except for the last one. Additionally, extra padding
|
||||
* bytes are added as required for alignment of child values.
|
||||
* </para>
|
||||
* <para>
|
||||
* Variants use the same amount of space as the item inside of the
|
||||
* variant, plus 1 byte, plus the length of the type string for the
|
||||
* item inside the variant.
|
||||
* </para>
|
||||
* <para>
|
||||
* As an example, consider a dictionary mapping strings to variants.
|
||||
* In the case that the dictionary is empty, 0 bytes are required for
|
||||
* the serialisation.
|
||||
* </para>
|
||||
* <para>
|
||||
* If we add an item "width" that maps to the int32 value of 500 then
|
||||
* we will use 4 byte to store the int32 (so 6 for the variant
|
||||
* containing it) and 6 bytes for the string. The variant must be
|
||||
* aligned to 8 after the 6 bytes of the string, so that's 2 extra
|
||||
* bytes. 6 (string) + 2 (padding) + 6 (variant) is 14 bytes used
|
||||
* for the dictionary entry. An additional 1 byte is added to the
|
||||
* array as a framing offset making a total of 15 bytes.
|
||||
* </para>
|
||||
* <para>
|
||||
* If we add another entry, "title" that maps to a nullable string
|
||||
* that happens to have a value of null, then we use 0 bytes for the
|
||||
* null value (and 3 bytes for the variant to contain it along with
|
||||
* its type string) plus 6 bytes for the string. Again, we need 2
|
||||
* padding bytes. That makes a total of 6 + 2 + 3 = 11 bytes.
|
||||
* </para>
|
||||
* <para>
|
||||
* We now require extra padding between the two items in the array.
|
||||
* After the 14 bytes of the first item, that's 2 bytes required. We
|
||||
* now require 2 framing offsets for an extra two bytes. 14 + 2 + 11
|
||||
* + 2 = 29 bytes to encode the entire two-item dictionary.
|
||||
* </para>
|
||||
* </refsect3>
|
||||
* <refsect3>
|
||||
* <title>Type Information Cache</title>
|
||||
* <para>
|
||||
* For each GVariant type that currently exists in the program a type
|
||||
* information structure is kept in the type information cache. The
|
||||
* type information structure is required for rapid deserialisation.
|
||||
* </para>
|
||||
* <para>
|
||||
* Continuing with the above example, if a #GVariant exists with the
|
||||
* type "a{sv}" then a type information struct will exist for
|
||||
* "a{sv}", "{sv}", "s", and "v". Multiple uses of the same type
|
||||
* will share the same type information. Additionally, all
|
||||
* single-digit types are stored in read-only static memory and do
|
||||
* not contribute to the writable memory footprint of a program using
|
||||
* #GVariant.
|
||||
* </para>
|
||||
* <para>
|
||||
* Aside from the type information structures stored in read-only
|
||||
* memory, there are two forms of type information. One is used for
|
||||
* container types where there is a single element type: arrays and
|
||||
* maybe types. The other is used for container types where there
|
||||
* are multiple element types: tuples and dictionary entries.
|
||||
* </para>
|
||||
* <para>
|
||||
* Array type info structures are 6 * sizeof (void *), plus the
|
||||
* memory required to store the type string itself. This means that
|
||||
* on 32-bit systems, the cache entry for "a{sv}" would require 30
|
||||
* bytes of memory (plus malloc overhead).
|
||||
* </para>
|
||||
* <para>
|
||||
* Tuple type info structures are 6 * sizeof (void *), plus 4 *
|
||||
* sizeof (void *) for each item in the tuple, plus the memory
|
||||
* required to store the type string itself. A 2-item tuple, for
|
||||
* example, would have a type information structure that consumed
|
||||
* writable memory in the size of 14 * sizeof (void *) (plus type
|
||||
* string) This means that on 32-bit systems, the cache entry for
|
||||
* "{sv}" would require 61 bytes of memory (plus malloc overhead).
|
||||
* </para>
|
||||
* <para>
|
||||
* This means that in total, for our "a{sv}" example, 91 bytes of
|
||||
* type information would be allocated.
|
||||
* </para>
|
||||
* <para>
|
||||
* The type information cache, additionally, uses a #GHashTable to
|
||||
* store and lookup the cached items and stores a pointer to this
|
||||
* hash table in static storage. The hash table is freed when there
|
||||
* are zero items in the type cache.
|
||||
* </para>
|
||||
* <para>
|
||||
* Although these sizes may seem large it is important to remember
|
||||
* that a program will probably only have a very small number of
|
||||
* different types of values in it and that only one type information
|
||||
* structure is required for many different values of the same type.
|
||||
* </para>
|
||||
* </refsect3>
|
||||
* <refsect3>
|
||||
* <title>Buffer Management Memory</title>
|
||||
* <para>
|
||||
* #GVariant uses an internal buffer management structure to deal
|
||||
* with the various different possible sources of serialised data
|
||||
* that it uses. The buffer is responsible for ensuring that the
|
||||
* correct call is made when the data is no longer in use by
|
||||
* #GVariant. This may involve a g_free() or a g_slice_free() or
|
||||
* even g_mapped_file_unref().
|
||||
* </para>
|
||||
* <para>
|
||||
* One buffer management structure is used for each chunk of
|
||||
* serialised data. The size of the buffer management structure is 4
|
||||
* * (void *). On 32bit systems, that's 16 bytes.
|
||||
* </para>
|
||||
* </refsect3>
|
||||
* <refsect3>
|
||||
* <title>GVariant structure</title>
|
||||
* <para>
|
||||
* The size of a #GVariant structure is 6 * (void *). On 32 bit
|
||||
* systems, that's 24 bytes.
|
||||
* </para>
|
||||
* <para>
|
||||
* #GVariant structures only exist if they are explicitly created
|
||||
* with API calls. For example, if a #GVariant is constructed out of
|
||||
* serialised data for the example given above (with the dictionary)
|
||||
* then although there are 9 individual values that comprise the
|
||||
* entire dictionary (two keys, two values, two variants containing
|
||||
* the values, two dictionary entries, plus the dictionary itself),
|
||||
* only 1 #GVariant instance exists -- the one referring to the
|
||||
* dictionary.
|
||||
* </para>
|
||||
* <para>
|
||||
* If calls are made to start accessing the other values then
|
||||
* #GVariant instances will exist for those values only for as long
|
||||
* as they are in use (ie: until you call g_variant_unref()). The
|
||||
* type information is shared. The serialised data and the buffer
|
||||
* management structure for that serialised data is shared by the
|
||||
* child.
|
||||
* </para>
|
||||
* </refsect3>
|
||||
* <refsect3>
|
||||
* <title>Summary</title>
|
||||
* <para>
|
||||
* To put the entire example together, for our dictionary mapping
|
||||
* strings to variants (with two entries, as given above), we are
|
||||
* using 91 bytes of memory for type information, 29 byes of memory
|
||||
* for the serialised data, 16 bytes for buffer management and 24
|
||||
* bytes for the #GVariant instance, or a total of 160 bytes, plus
|
||||
* malloc overhead. If we were to use g_variant_get_child_value() to
|
||||
* access the two dictionary entries, we would use an additional 48
|
||||
* bytes. If we were to have other dictionaries of the same type, we
|
||||
* would use more memory for the serialised data and buffer
|
||||
* management for those dictionaries, but the type information would
|
||||
* be shared.
|
||||
* </para>
|
||||
* </refsect3>
|
||||
* </refsect2>
|
||||
* ## Memory Use
|
||||
*
|
||||
* #GVariant tries to be quite efficient with respect to memory use.
|
||||
* This section gives a rough idea of how much memory is used by the
|
||||
* current implementation. The information here is subject to change
|
||||
* in the future.
|
||||
*
|
||||
* The memory allocated by #GVariant can be grouped into 4 broad
|
||||
* purposes: memory for serialised data, memory for the type
|
||||
* information cache, buffer management memory and memory for the
|
||||
* #GVariant structure itself.
|
||||
*
|
||||
* ## Serialised Data Memory
|
||||
*
|
||||
* This is the memory that is used for storing GVariant data in
|
||||
* serialised form. This is what would be sent over the network or
|
||||
* what would end up on disk.
|
||||
*
|
||||
* The amount of memory required to store a boolean is 1 byte. 16,
|
||||
* 32 and 64 bit integers and double precision floating point numbers
|
||||
* use their "natural" size. Strings (including object path and
|
||||
* signature strings) are stored with a nul terminator, and as such
|
||||
* use the length of the string plus 1 byte.
|
||||
*
|
||||
* Maybe types use no space at all to represent the null value and
|
||||
* use the same amount of space (sometimes plus one byte) as the
|
||||
* equivalent non-maybe-typed value to represent the non-null case.
|
||||
*
|
||||
* Arrays use the amount of space required to store each of their
|
||||
* members, concatenated. Additionally, if the items stored in an
|
||||
* array are not of a fixed-size (ie: strings, other arrays, etc)
|
||||
* then an additional framing offset is stored for each item. The
|
||||
* size of this offset is either 1, 2 or 4 bytes depending on the
|
||||
* overall size of the container. Additionally, extra padding bytes
|
||||
* are added as required for alignment of child values.
|
||||
*
|
||||
* Tuples (including dictionary entries) use the amount of space
|
||||
* required to store each of their members, concatenated, plus one
|
||||
* framing offset (as per arrays) for each non-fixed-sized item in
|
||||
* the tuple, except for the last one. Additionally, extra padding
|
||||
* bytes are added as required for alignment of child values.
|
||||
*
|
||||
* Variants use the same amount of space as the item inside of the
|
||||
* variant, plus 1 byte, plus the length of the type string for the
|
||||
* item inside the variant.
|
||||
*
|
||||
* As an example, consider a dictionary mapping strings to variants.
|
||||
* In the case that the dictionary is empty, 0 bytes are required for
|
||||
* the serialisation.
|
||||
*
|
||||
* If we add an item "width" that maps to the int32 value of 500 then
|
||||
* we will use 4 byte to store the int32 (so 6 for the variant
|
||||
* containing it) and 6 bytes for the string. The variant must be
|
||||
* aligned to 8 after the 6 bytes of the string, so that's 2 extra
|
||||
* bytes. 6 (string) + 2 (padding) + 6 (variant) is 14 bytes used
|
||||
* for the dictionary entry. An additional 1 byte is added to the
|
||||
* array as a framing offset making a total of 15 bytes.
|
||||
*
|
||||
* If we add another entry, "title" that maps to a nullable string
|
||||
* that happens to have a value of null, then we use 0 bytes for the
|
||||
* null value (and 3 bytes for the variant to contain it along with
|
||||
* its type string) plus 6 bytes for the string. Again, we need 2
|
||||
* padding bytes. That makes a total of 6 + 2 + 3 = 11 bytes.
|
||||
*
|
||||
* We now require extra padding between the two items in the array.
|
||||
* After the 14 bytes of the first item, that's 2 bytes required. We
|
||||
* now require 2 framing offsets for an extra two bytes. 14 + 2 + 11
|
||||
* + 2 = 29 bytes to encode the entire two-item dictionary.
|
||||
*
|
||||
* ## Type Information Cache
|
||||
*
|
||||
* For each GVariant type that currently exists in the program a type
|
||||
* information structure is kept in the type information cache. The
|
||||
* type information structure is required for rapid deserialisation.
|
||||
*
|
||||
* Continuing with the above example, if a #GVariant exists with the
|
||||
* type "a{sv}" then a type information struct will exist for
|
||||
* "a{sv}", "{sv}", "s", and "v". Multiple uses of the same type
|
||||
* will share the same type information. Additionally, all
|
||||
* single-digit types are stored in read-only static memory and do
|
||||
* not contribute to the writable memory footprint of a program using
|
||||
* #GVariant.
|
||||
*
|
||||
* Aside from the type information structures stored in read-only
|
||||
* memory, there are two forms of type information. One is used for
|
||||
* container types where there is a single element type: arrays and
|
||||
* maybe types. The other is used for container types where there
|
||||
* are multiple element types: tuples and dictionary entries.
|
||||
*
|
||||
* Array type info structures are 6 * sizeof (void *), plus the
|
||||
* memory required to store the type string itself. This means that
|
||||
* on 32-bit systems, the cache entry for "a{sv}" would require 30
|
||||
* bytes of memory (plus malloc overhead).
|
||||
*
|
||||
* Tuple type info structures are 6 * sizeof (void *), plus 4 *
|
||||
* sizeof (void *) for each item in the tuple, plus the memory
|
||||
* required to store the type string itself. A 2-item tuple, for
|
||||
* example, would have a type information structure that consumed
|
||||
* writable memory in the size of 14 * sizeof (void *) (plus type
|
||||
* string) This means that on 32-bit systems, the cache entry for
|
||||
* "{sv}" would require 61 bytes of memory (plus malloc overhead).
|
||||
*
|
||||
* This means that in total, for our "a{sv}" example, 91 bytes of
|
||||
* type information would be allocated.
|
||||
*
|
||||
* The type information cache, additionally, uses a #GHashTable to
|
||||
* store and lookup the cached items and stores a pointer to this
|
||||
* hash table in static storage. The hash table is freed when there
|
||||
* are zero items in the type cache.
|
||||
*
|
||||
* Although these sizes may seem large it is important to remember
|
||||
* that a program will probably only have a very small number of
|
||||
* different types of values in it and that only one type information
|
||||
* structure is required for many different values of the same type.
|
||||
*
|
||||
* ## Buffer Management Memory
|
||||
*
|
||||
* #GVariant uses an internal buffer management structure to deal
|
||||
* with the various different possible sources of serialised data
|
||||
* that it uses. The buffer is responsible for ensuring that the
|
||||
* correct call is made when the data is no longer in use by
|
||||
* #GVariant. This may involve a g_free() or a g_slice_free() or
|
||||
* even g_mapped_file_unref().
|
||||
*
|
||||
* One buffer management structure is used for each chunk of
|
||||
* serialised data. The size of the buffer management structure
|
||||
* is 4 * (void *). On 32-bit systems, that's 16 bytes.
|
||||
*
|
||||
* ## GVariant structure
|
||||
*
|
||||
* The size of a #GVariant structure is 6 * (void *). On 32-bit
|
||||
* systems, that's 24 bytes.
|
||||
*
|
||||
* #GVariant structures only exist if they are explicitly created
|
||||
* with API calls. For example, if a #GVariant is constructed out of
|
||||
* serialised data for the example given above (with the dictionary)
|
||||
* then although there are 9 individual values that comprise the
|
||||
* entire dictionary (two keys, two values, two variants containing
|
||||
* the values, two dictionary entries, plus the dictionary itself),
|
||||
* only 1 #GVariant instance exists -- the one referring to the
|
||||
* dictionary.
|
||||
*
|
||||
* If calls are made to start accessing the other values then
|
||||
* #GVariant instances will exist for those values only for as long
|
||||
* as they are in use (ie: until you call g_variant_unref()). The
|
||||
* type information is shared. The serialised data and the buffer
|
||||
* management structure for that serialised data is shared by the
|
||||
* child.
|
||||
*
|
||||
* ## Summary
|
||||
*
|
||||
* To put the entire example together, for our dictionary mapping
|
||||
* strings to variants (with two entries, as given above), we are
|
||||
* using 91 bytes of memory for type information, 29 byes of memory
|
||||
* for the serialised data, 16 bytes for buffer management and 24
|
||||
* bytes for the #GVariant instance, or a total of 160 bytes, plus
|
||||
* malloc overhead. If we were to use g_variant_get_child_value() to
|
||||
* access the two dictionary entries, we would use an additional 48
|
||||
* bytes. If we were to have other dictionaries of the same type, we
|
||||
* would use more memory for the serialised data and buffer
|
||||
* management for those dictionaries, but the type information would
|
||||
* be shared.
|
||||
*/
|
||||
|
||||
/* definition of GVariant structure is in gvariant-core.c */
|
||||
|
Loading…
x
Reference in New Issue
Block a user