JSON Object Lifecycle
Relevant source files
The following files were used as context for generating this wiki page:
The libfastjson library implements a reference-counting object model to manage the lifecycle of JSON entities in C. This model allows for the creation, manipulation, and automated destruction of complex JSON structures through shared ownership. Every JSON entity is represented as a fjson_object, which tracks its own reference count and provides specialized cleanup routines based on its underlying type (e.g., string, array, or object).
Sources: README.html:12-15, json_object.h:122-128, json_object_private.h:60-88
Object Creation and Initialization
JSON objects are instantiated with an initial reference count of 1. Creation occurs either through direct API calls for specific types or by parsing existing JSON data. The internal fjson_object_new function allocates the base structure and initializes type-specific function pointers for serialization and deletion.
Allocation and Type-Specific Constructors
The library provides dedicated constructors for each JSON type. When a new object is created, it is assigned a _delete pointer that points to a specific cleanup function (e.g., fjson_object_array_delete for arrays).
| Function | Resulting Type | Description |
|---|---|---|
fjson_object_new_object() | fjson_type_object | Creates an empty JSON object (key-value map). |
fjson_object_new_array() | fjson_type_array | Creates an empty JSON array. |
fjson_object_new_string(const char *s) | fjson_type_string | Creates a string object; copies the input string. |
fjson_object_new_int(int32_t i) | fjson_type_int | Creates a 64-bit integer object. |
fjson_object_new_double(double d) | fjson_type_double | Creates a floating-point object. |
fjson_object_new_boolean(fjson_bool b) | fjson_type_boolean | Creates a boolean object. |
Sources: json_object.c:237-251, json_object.c:380-388, json_object.c:595-603, json_object.h:215-220
Creation via Parsing
Objects are also created during the parsing process. The fjson_tokener scans input strings and dynamically builds the object tree using the constructors mentioned above.
The diagram shows the flow from a raw string to a structured fjson_object hierarchy managed by the tokener.
Sources: json_tokener.c:166-177, json_tokener.c:248-310
Reference Counting and Ownership
Ownership in libfastjson is managed via fjson_object_get and fjson_object_put. This mechanism ensures that memory is only freed when no other part of the system holds a reference to the object.
Reference Modification
fjson_object_get(): Increments the reference count. It must be called if a reference to an object is stored independently of its parent structure.fjson_object_put(): Decrements the reference count. If the count reaches zero, the object's specialized_deletefunction is invoked.
Sources: json_object.c:211-226, json_object.h:140-155
Ownership Transfer
Ownership typically transfers when an object is added to a container:
- Objects:
fjson_object_object_addtransfers ownership of the value to the parent object. - Arrays:
fjson_object_array_addorfjson_object_array_put_idxtransfers ownership to the array.
Sources: json_object.h:352-362, json_object.h:467-474
The sequence diagram illustrates how adding an object to a parent container shifts the responsibility for calling put to that parent.
Sources: json_object.c:221-226, json_object.c:486-506
Object Destruction
When the reference count reaches zero, the object's specific destructor is called. This process is recursive; for example, deleting an array will call fjson_object_put on all its elements.
Specialized Deletion Logic
Destruction logic varies by type to ensure all allocated sub-resources are freed:
- Strings: If the string length exceeds
LEN_DIRECT_STRING_DATA(32 bytes), the library frees the heap-allocated pointer ino.c_string.str.ptr. Otherwise, it is stored inline and requires no extra free. - Objects (Maps): Iterates through the internal
_fjson_child_pg(child pages) and frees both keys (if not constant) and values viafjson_object_put. - Arrays: Calls
array_list_free, which triggers a callback tofjson_object_putfor every element.
Sources: json_object.c:364-378, json_object.c:667-671, json_object_private.h:41-41
Data Structure for Object Storage
Internal objects use a paged structure for children to balance allocation frequency and space usage.
This diagram depicts the relationship between the base fjson_object and the paged storage used for the fjson_type_object type.
Sources: json_object_private.h:60-88, json_object.h:42-49
Summary
The lifecycle of an fjson_object begins with a constructor and ends when its reference count, managed through fjson_object_put, reaches zero. The system relies on a recursive cleanup strategy where containers manage the lifecycle of their children, ensuring complex JSON trees are disposed of correctly when the root reference is released.
Sources: json_object.c:219-226, json_object.c:364-378