Julia: `Serialization.serialize()` strings are not interned, causing duplication

Created on 6 Mar 2020  路  6Comments  路  Source: JuliaLang/julia

From https://discourse.julialang.org/t/serialization-serialize-strings-are-not-interned-de-duplication/35626

@vtjnash asked me to open this as an Issue on the repo. Can we implement string interning when serializing (large) strings? Can we maybe share this logic with the interning for Symbols? Thanks!

--
Copied from discourse:

julia> using Humanize  # For pretty printing, not necessary for reproduction

julia> using Serialization

julia> struct StringHolder
           a::String
           b::String
       end

julia> s = join(rand('a':'z', 1024*1024)); # 1 MiB string

julia> sh = StringHolder(s, s);

julia> Humanize.datasize(Base.summarysize(sh), style=:bin)  # The string is shared in memory.
"1.0 MiB"

julia> serialize("/tmp/sh", sh)

julia> run(`ls -lh /tmp/sh`)  # Size on disk is 2 MiB! (duplicated!)
-rw-r--r--  1 nathan.daly  wheel   2.0M Mar  6 00:06 /tmp/sh
Process(`ls -lh /tmp/sh`, ProcessExited(0))

julia> sh_deserialized = deserialize("/tmp/sh");   # It's big now! :'(

julia> Humanize.datasize(Base.summarysize(sh_deserialized), style=:bin)
"2.0 MiB"

Most helpful comment

Yes, all we have to do is conditionally use the backreference table in the Serializer object in the serialize method for String. Should be a fairly easy change. What do we think the size cutoff should be?

All 6 comments

Yes, all we have to do is conditionally use the backreference table in the Serializer object in the serialize method for String. Should be a fairly easy change. What do we think the size cutoff should be?

What do we think the size cutoff should be?

I'm not 100% sure, but my gut reaction says it should be something like the pointer size? That is, if it'd take more space to store the reference than it would just to store the string, it's probably better just to store the string.

On the other hand, we may even want to go smaller than that, since this _will_ still lead to potentially _lots_ of tiny allocations when deserializing when we could have instead been sharing those (albeit tiny) strings. Maybe even just like 8 or 16 bytes or something small?

@vtjnash told me there's already some kind of size cutoff for Symbol interning, so probably just doing whatever that does makes sense.

Quick ping on this again now that the weekend is over:

Do you have a sense for how difficult this will be to fix? Our CI servers have been running out of disk space because of the large strings we're persisting (caused by simulated user data, which has recently gotten larger).

If you think it can be fixed on the order of a couple days, we will wait for a fix from you. If not, we will probably have to figure out a way to fix this ourselves, maybe by switching off of julia's serialization, and implementing our own custom serialization or something?

So if possible, can you provide guidance on how we should proceed? Should we wait for a fix for this or try to create our own bandaid? :) Thanks!! 鉂わ笍

Ok, I didn't know this was a "we're running out of disk space" scenario :) Good to know the urgency. I'll work on it now.

In case it's applicable, a possible short-term workaround is to wrap the strings in Refs, so that shared references are retained.

Sorry, i didn't mean to rush you!! Thanks for the support, Jeff. :)

It was more just that I genuinely was trying to figure out whether we should plan a workaround or wait for you. It seems like you think it'll be relatively easy to tackle? :) Thanks a bunch!!!!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

m-j-w picture m-j-w  路  3Comments

Keno picture Keno  路  3Comments

TotalVerb picture TotalVerb  路  3Comments

helgee picture helgee  路  3Comments

wilburtownsend picture wilburtownsend  路  3Comments