From 8c6b0ab3f7e437362112eeaf83a566475b85d27c Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Thu, 20 Sep 2007 00:13:35 -0400 Subject: Add support for compacting DBusStrings to release wasted memory. 2007-09-19 Ryan Lortie * dbus/dbus-string.[ch] (compact, _dbus_string_compact, _dbus_string_lock): new compact function to free up allocated memory that is no longer used. * dbus/dbus-message.c (load_message): call _dbus_string_compact on the message loader buffer. * dbus/dbus-transport-socket.c (do_reading, do_writing): call _dbus_string_compact on the incoming/outgoing "encoded" buffers. * dbus/dbus-string-util.c (_dbus_string_test): add a few tests for string compacting. --- dbus/dbus-message.c | 3 +++ dbus/dbus-string-util.c | 56 +++++++++++++++++++++++++++++++++++++++ dbus/dbus-string.c | 63 +++++++++++++++++++++++++++++++++----------- dbus/dbus-string.h | 2 ++ dbus/dbus-transport-socket.c | 2 ++ 5 files changed, 110 insertions(+), 16 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 91f6ebec..cd447985 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -3545,6 +3545,9 @@ load_message (DBusMessageLoader *loader, _dbus_string_delete (&loader->data, 0, header_len + body_len); + /* don't waste more than 2k of memory */ + _dbus_string_compact (&loader->data, 2048); + _dbus_assert (_dbus_string_get_length (&message->header.data) == header_len); _dbus_assert (_dbus_string_get_length (&message->body) == body_len); diff --git a/dbus/dbus-string-util.c b/dbus/dbus-string-util.c index cee02c4c..492c5289 100644 --- a/dbus/dbus-string-util.c +++ b/dbus/dbus-string-util.c @@ -790,6 +790,62 @@ _dbus_string_test (void) _dbus_string_free (&str); _dbus_string_free (&line); } + + { + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("no memory"); + + for (i = 0; i < 10000; i++) + if (!_dbus_string_append (&str, "abcdefghijklmnopqrstuvwxyz")) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_set_length (&str, 10)) + _dbus_assert_not_reached ("failed to set length"); + + /* actually compact */ + if (!_dbus_string_compact (&str, 2048)) + _dbus_assert_not_reached ("failed to compact after set_length"); + + /* peek inside to make sure it worked */ + if (((DBusRealString *)&str)->allocated > 30) + _dbus_assert_not_reached ("compacting string didn't do anything"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij")) + _dbus_assert_not_reached ("unexpected content after compact"); + + /* compact nothing */ + if (!_dbus_string_compact (&str, 2048)) + _dbus_assert_not_reached ("failed to compact 2nd time"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij")) + _dbus_assert_not_reached ("unexpected content after 2nd compact"); + + /* and make sure it still works...*/ + if (!_dbus_string_append (&str, "123456")) + _dbus_assert_not_reached ("failed to append after compact"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij123456")) + _dbus_assert_not_reached ("unexpected content after append"); + + /* after growing automatically, this should do nothing */ + if (!_dbus_string_compact (&str, 20000)) + _dbus_assert_not_reached ("failed to compact after grow"); + + /* but this one will do something */ + if (!_dbus_string_compact (&str, 0)) + _dbus_assert_not_reached ("failed to compact after grow"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij123456")) + _dbus_assert_not_reached ("unexpected content"); + + if (!_dbus_string_append (&str, "!@#$%")) + _dbus_assert_not_reached ("failed to append after compact"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij123456!@#$%")) + _dbus_assert_not_reached ("unexpected content"); + + _dbus_string_free (&str); + } return TRUE; } diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 62ac8c31..000b4f64 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -271,6 +271,32 @@ _dbus_string_free (DBusString *str) real->invalid = TRUE; } +static dbus_bool_t +compact (DBusRealString *real, + int max_waste) +{ + unsigned char *new_str; + int new_allocated; + int waste; + + waste = real->allocated - (real->len + _DBUS_STRING_ALLOCATION_PADDING); + + if (waste <= max_waste) + return TRUE; + + new_allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING; + + new_str = dbus_realloc (real->str - real->align_offset, new_allocated); + if (_DBUS_UNLIKELY (new_str == NULL)) + return FALSE; + + real->str = new_str + real->align_offset; + real->allocated = new_allocated; + fixup_alignment (real); + + return TRUE; +} + #ifdef DBUS_BUILD_TESTS /* Not using this feature at the moment, * so marked DBUS_BUILD_TESTS-only @@ -295,22 +321,7 @@ _dbus_string_lock (DBusString *str) * we know we won't change the string further */ #define MAX_WASTE 48 - if (real->allocated - MAX_WASTE > real->len) - { - unsigned char *new_str; - int new_allocated; - - new_allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING; - - new_str = dbus_realloc (real->str - real->align_offset, - new_allocated); - if (new_str != NULL) - { - real->str = new_str + real->align_offset; - real->allocated = new_allocated; - fixup_alignment (real); - } - } + compact (real, MAX_WASTE); } #endif /* DBUS_BUILD_TESTS */ @@ -361,6 +372,26 @@ reallocate_for_length (DBusRealString *real, return TRUE; } +/** + * Compacts the string to avoid wasted memory. Wasted memory is + * memory that is allocated but not actually required to store the + * current length of the string. The compact is only done if more + * than the given amount of memory is being wasted (otherwise the + * waste is ignored and the call does nothing). + * + * @param str the string + * @param max_waste the maximum amount of waste to ignore + * @returns #FALSE if the compact failed due to realloc failure + */ +dbus_bool_t +_dbus_string_compact (DBusString *str, + int max_waste) +{ + DBUS_STRING_PREAMBLE (str); + + return compact (real, max_waste); +} + static dbus_bool_t set_length (DBusRealString *real, int new_length) diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index 076fed63..b0100f3a 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -73,6 +73,8 @@ dbus_bool_t _dbus_string_init_preallocated (DBusString *str, int allocate_size); void _dbus_string_free (DBusString *str); void _dbus_string_lock (DBusString *str); +dbus_bool_t _dbus_string_compact (DBusString *str, + int max_waste); #ifndef _dbus_string_get_data char* _dbus_string_get_data (DBusString *str); #endif /* _dbus_string_get_data */ diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c index a31c1597..f6d0e9c2 100644 --- a/dbus/dbus-transport-socket.c +++ b/dbus/dbus-transport-socket.c @@ -642,6 +642,7 @@ do_writing (DBusTransport *transport) { socket_transport->message_bytes_written = 0; _dbus_string_set_length (&socket_transport->encoded_outgoing, 0); + _dbus_string_compact (&socket_transport->encoded_outgoing, 2048); _dbus_connection_message_sent (transport->connection, message); @@ -733,6 +734,7 @@ do_reading (DBusTransport *transport) _dbus_string_get_length (buffer) - orig_len); _dbus_string_set_length (&socket_transport->encoded_incoming, 0); + _dbus_string_compact (&socket_transport->encoded_incoming, 2048); } } else -- cgit