Deprecated: Optional parameter $content declared before required parameter $post is implicitly treated as a required parameter in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/functions.php on line 840

Deprecated: Creation of dynamic property wpdb::$categories is deprecated in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$post2cat is deprecated in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$link2cat is deprecated in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/wp-db.php on line 668

Deprecated: Return type of WP_Theme::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-theme.php on line 553

Deprecated: Return type of WP_Theme::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-theme.php on line 594

Deprecated: Return type of WP_Theme::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-theme.php on line 534

Deprecated: Return type of WP_Theme::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-theme.php on line 543

Warning: Private methods cannot be final as they are never overridden by other classes in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-session-tokens.php on line 69

Deprecated: Using ${var} in strings is deprecated, use {$var} instead in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/comment-template.php on line 1720

Deprecated: Optional parameter $object_id declared before required parameter $taxonomy is implicitly treated as a required parameter in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/nav-menu.php on line 1060

Deprecated: Return type of WP_REST_Request::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php on line 934

Deprecated: Return type of WP_REST_Request::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php on line 954

Deprecated: Return type of WP_REST_Request::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php on line 966

Deprecated: Return type of WP_REST_Request::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php on line 977

Deprecated: Return type of WP_Block_List::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 151

Deprecated: Return type of WP_Block_List::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 175

Deprecated: Return type of WP_Block_List::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 164

Deprecated: Return type of WP_Block_List::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 186

Deprecated: Return type of WP_Block_List::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 138

Deprecated: Return type of WP_Block_List::offsetExists($index) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 75

Deprecated: Return type of WP_Block_List::offsetGet($index) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 89

Deprecated: Return type of WP_Block_List::offsetSet($index, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 110

Deprecated: Return type of WP_Block_List::offsetUnset($index) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 127

Deprecated: Return type of WP_Block_List::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/class-wp-block-list.php on line 199

Deprecated: Optional parameter $block_name declared before required parameter $block_content is implicitly treated as a required parameter in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/blocks.php on line 405

Deprecated: Creation of dynamic property WP_REST_Autosaves_Controller::$rest_namespace is deprecated in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 70

Deprecated: Creation of dynamic property WP_REST_Autosaves_Controller::$rest_namespace is deprecated in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 70

Deprecated: Creation of dynamic property WP_REST_Autosaves_Controller::$rest_namespace is deprecated in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 70

Warning: Cannot modify header information - headers already sent by (output started at /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php:29) in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-server.php on line 1378

Warning: Cannot modify header information - headers already sent by (output started at /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php:29) in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-server.php on line 1378

Warning: Cannot modify header information - headers already sent by (output started at /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php:29) in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-server.php on line 1378

Warning: Cannot modify header information - headers already sent by (output started at /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php:29) in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-server.php on line 1378

Warning: Cannot modify header information - headers already sent by (output started at /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php:29) in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-server.php on line 1378

Warning: Cannot modify header information - headers already sent by (output started at /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php:29) in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-server.php on line 1378

Deprecated: ltrim(): Passing null to parameter #1 ($string) of type string is deprecated in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/wp-db.php on line 3008

Warning: Cannot modify header information - headers already sent by (output started at /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php:29) in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-server.php on line 1378

Warning: Cannot modify header information - headers already sent by (output started at /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-request.php:29) in /vhost/r/o/t/rottedfrog.co.uk/www/wp-includes/rest-api/class-wp-rest-server.php on line 1378
{"id":10,"date":"2014-02-22T17:11:12","date_gmt":"2014-02-22T17:11:12","guid":{"rendered":"http:\/\/www.rottedfrog.co.uk\/?p=10"},"modified":"2020-05-24T20:11:19","modified_gmt":"2020-05-24T20:11:19","slug":"when-more-memory-is-less","status":"publish","type":"post","link":"https:\/\/www.rottedfrog.co.uk\/?p=10","title":{"rendered":"When more memory is less"},"content":{"rendered":"\n

Quick question; when can increasing the size of your data structures lead to less memory being allocated?<\/p>\n\n\n\n

While you consider your answer to the conundrum, I’ll lay out the scenario for mine.<\/p>\n\n\n\n

I have a Lexer I’ve written in C# for an expression evaluation language. A Lexer (more properly a lexical analyzer, sometimes called a tokeniser) takes a string of text and splits it into tokens which can be usefully consumed by a parser to do something cool.<\/p>\n\n\n\n

Now the Lex function on my Lexer class takes as its argument a single string, and returns an IEnumerable.
Tokens look like this:<\/p>\n\n\n\n

struct Token\n{\n  public string Text;\n  public int Position;\n  public TokenType Type;\n}<\/pre>\n\n\n\n

Text is the part of the original expression which this token represents – I take a substring of the original string.<\/p>\n\n\n\n

Position is where the token occurs in the original string – Used for producing useful error messages when parsing fails.<\/p>\n\n\n\n

TokenType is an enum which specifies what sort of token it is. The most functionally important part of the lexer’s output, but you can ignore it for the purposes of this discussion.<\/p>\n\n\n\n

Now I’m parsing 2 large text files with this lexer (around 35MB of data). Memory requirements for this and the other data structures involved are just under 500MB – so non trivial.<\/p>\n\n\n\n

When looking at performance I noticed the huge number of memory allocations that were being done by the lexer. Not I’m parsing over 300,000 expressions with this lexer, so there are well over four million tokens being generated. The tokens are kept alive as long as the files are open in the app, as I use them for more than just parsing. That means I have over four million strings allocated. Thinking about it that way, I decided to change my implementation of Token to the following:<\/p>\n\n\n\n

struct Token\n{\n   public string Expression;\n   public int Position;\n   public int Length;\n   public TokenType Type;\n   public Text { get { return Expression.Substring(Position, Length); } }\n}<\/pre>\n\n\n\n

I’ve added a Line and a Length field. Notice that text is now a property with a custom getter and no backing storage and hence doesn’t take up memory. Total net change in size is a 4 byte increase.<\/p>\n\n\n\n

I refactor my code to store the entire expression in the Expression field and the length of the token in the Length field. The text property gives the same result as before, but computes its value from the other information in the token.<\/p>\n\n\n\n

So my four million tokens now take up an extra 16MB of space right?<\/p>\n\n\n\n

Actually the program posted a 90MB decrease in memory usage. That’s nearly a full 20% less. How come?<\/p>\n\n\n\n

This optimisation is all about strings, and relies on two factors of strings – immutability and “referenceness”.<\/p>\n\n\n\n

Strings are immutable reference objects. This means you are really just passing around pointers to memory that doesn’t change. Once it’s been allocated it doesn’t change until it gets collected by the garbage collector. So I can have lots of copies of that string without ever needing to allocate more memory. If the string is changed somewhere, a new string is allocated and used instead, preserving the original, so all other references are safe.<\/p>\n\n\n\n

So I re-use my already allocated expression string instead of allocating a new one. The net result is 4 million less allocations (10% speed boost) and 90MB less memory allocated. Why 90MB for 35MB of text data? Well my text data is stored in UTF-8 where as internally a .NET string is encoded as UTF-16, so they are approximately twice as big in memory. They have a int length indicator, which is another 4 bytes times the length of the string, which adds 16MB. So that’s about 86MB, which is exactly the same as 90MB when you are writing a blog post.<\/p>\n","protected":false},"excerpt":{"rendered":"

Quick question; when can increasing the size of your data structures lead to less memory being allocated? While you consider your answer to the conundrum, I’ll lay out the scenario for mine. I have a Lexer I’ve written in C# for an expression evaluation language. A Lexer (more properly a lexical analyzer, sometimes called a … <\/p>\n