--- title: this pointers --- We specify exactly which function and arguments are to be introspected through a ***probe specification*** (terminology borrowed from [DTrace](https://en.wikipedia.org/wiki/DTrace)). It's simply a colon delimited tuple that specifies exactly what object we are interested in and where in the code we want to observe it. For example, to introspect the `AddressBook` object we can measure it at the entry to its `DumpContacts()` method and the specification would be: ``` entry:_ZN11AddressBook12DumpContactsEv:this ``` There are a few points to note here: We use the `oid` debugger to capture the object itself from the address book application. Every second a contact is added to the address book with the `AddContact()` method and the address book is dumped with the `DumpContacts()` method. After running for a minute or so let's capture the Address book object: ``` $ build/oid -S 'entry:_ZN11AddressBook12DumpContactsEv:this' -p `pgrep addrbook` -c build/oid-cfg.toml -J Attached to pid 4039830 SUCCESS ``` The `-J` flag instructed `oid` to dump the captured objects introspection data in a JSON file: ``` $ ~/object-introspection# ls -l oid_out.json -rw-r--r-- 1 root root 78975 Dec 16 20:35 oid_out.json ``` This is a simple object but the resulting JSON becomes quite large when more than a handful of contacts have been added. Let's examine some sections to see what we can glean about the object that has been captured: ``` $ jq . oid_out.json [ { "name": "this", "typePath": "this", "typeName": "AddressBook", "isTypedef": false, "staticSize": 64, "dynamicSize": 23185, "paddingSavingsSize": 4, "members": [ ``` The root type is an AddressBook object as we'd expect and it has a static footprint of 64 bytes with its data members in total having a dynamic memory footprint of 23185 bytes. The first member is simply an integer for the rev data member which has a 4 byte static memory footprint on this platform. ``` "members": [ { "name": "rev", "typePath": "rev", "typeName": "int", "isTypedef": false, "staticSize": 4, "dynamicSize": 0 }, ``` Next we have a std::string object for the top level Owner member. Note how this is expanded down to the base types which show the string has a static footprint of 32 bytes but we can see that it is empty as it has a dynamicSize of 0. The capacity of 15 bytes shows the Short String optimization buffer in a libstdc++ std::string object. ``` { "name": "Owner", "typePath": "Owner", "typeName": "string", "isTypedef": true, "staticSize": 32, "dynamicSize": 0, "members": [ { "name": "", "typePath": "", "typeName": "basic_string, std::alloca tor >", "isTypedef": false, "staticSize": 32, "dynamicSize": 0, "length": 0, "capacity": 15, "elementStaticSize": 1 } ] }, ``` The Entries member gets a bit more interesting as it introduces usage of a C++ container class, the std::vector. More accurately, it is a vector of Contact objects as can be seen in the typeName JSON member for the root of the Entries object shown below. Note that the vector currently has an allocated capacity of 128 Contact elements of which 71 are actual Contact objects. The 23185 bytes of dynamically allocated objects in the vector is composed of the 71 x 96 byte Contact objects plus whatever memory that has been dynamically allocated for string content in those objects: ``` { "name": "Entries", "typePath": "Entries", "typeName": "vector >", "isTypedef": false, "staticSize": 24, "dynamicSize": 23185, "pointer": 140720550450568, "length": 71, "capacity": 128, "elementStaticSize": 96, ``` For the sake of brevity let's just inspect the first `Contact` object shown below. It's static footprint at 96 bytes is the three strings at 32 bytes each. We can see that the first and third string have strings larger than the 15 bytes allocated for the short string optimization buffer and are therefore allocated in dynamic memory that is external to the string objects themselves. The second string has no dynamic memory allocated as the 14 byte character sequence it is housing fits within the 15 byte pre-allocated buffer: ``` "members": [ { "name": "", "typePath": "Contact[]", "typeName": "Contact", "isTypedef": false, "staticSize": 96, "dynamicSize": 65, "members": [ { "name": "firstName", "typePath": "firstName", "typeName": "string", "isTypedef": true, "staticSize": 32, "dynamicSize": 35, "members": [ { "name": "", "typePath": "", "typeName": "basic_string, std::allocator >", "isTypedef": false, "staticSize": 32, "dynamicSize": 35, "length": 35, "capacity": 35, "elementStaticSize": 1 } ] }, { "name": "lastName", "typePath": "lastName", "typeName": "string", "isTypedef": true, "staticSize": 32, "dynamicSize": 0, "members": [ { "name": "", "typePath": "", "typeName": "basic_string, std::allocator >", "isTypedef": false, "staticSize": 32, "dynamicSize": 0, "length": 14, "capacity": 15, "elementStaticSize": 1 } ] }, { "name": "number", "typePath": "number", "typeName": "string", "isTypedef": true, "staticSize": 32, "dynamicSize": 30, "members": [ { "name": "", "typePath": "", "typeName": "basic_string, std::allocator >", "isTypedef": false, "staticSize": 32, "dynamicSize": 30, "length": 18, "capacity": 30, "elementStaticSize": 1 } ] } ``` In total we have 71 `Contact` objects introspected here and each can be analyzed as we have done above: ``` $ ~/object-introspection# jq . /tmp/oit.oit.json.fmt | grep -c "\"typeName\": \"Contact\"" 71 ```