String Deduplication – A new feature in Java 8 Update 20
blog.codecentric.de
blog.codecentric.de
And "all" of this would be solved by having a proper way of doing array slicing - for things like substring's previous worst case (something like a single character being referenced in a substring holding up a gigabyte+-sized string) Java's garbage collector could recognize that the array was only referenced through slices of part of the array, copy that section into another array (updating references to it), and free the large one.
Also, Java's lack of a way to specify that a class is immutable (and that all children classes thereof must also be) is frustrating. Because optimizations like this can and should apply to more than just strings!
ByteBuffer and CharBuffer are a way of doing array slicing. CharBuffer even implements Appendable and CharSequence so it's half way polymorphic with String.
I sometimes whish there would be multiple String classes tailored for specific purposes like there are Collection classes. Especially a String class for ASCII strings that uses only eight bytes per character.
Do you really mean Iterable<Character> and not Iterable<Integer>. Because a Unicode code point can spawn two chars.
But I've said a lot on the subject of strings already:
https://news.ycombinator.com/item?id=8198811
https://news.ycombinator.com/item?id=8066158
https://news.ycombinator.com/item?id=7606084
Most of those changes don't have any relation whatsoever with the Java Language Specification or Java Virtual Machine Specification.
You do have a point, although it does not refute mine. However, Oracle's implementation is the most widespread - the chances are high that at some point most non-specialized Java code will be run on Oracle's implementation.
- Real time deployment scenarios
- J2EE containers, which tend to work best with the respective vendor JVM
- factory control JVMs
- car infotaiment JVMs
- smart card JVMs
- Compilation to native code
- Android
- Embedded deployments like MicroEJ
- Commercial UNIX systems
- Mainframes
- ...
One of the key activities in programming is reasoning about time and space cost, and this is a space optimization that's nondeterministic. It kicks in sometimes, or sometimes not at all, and happens behind the scenes at garbage collection time when it's nearly invisible. If you're sloppy, your program may have a huge asymptotic space usage, and this may paper over it. But the impl has heuristics, it may not work all the time -- even their example program needed Thread.sleep() calls! Unpredictable semantics help nobody. So I always liked explicit string interning (whatup, Lisp!).
All the same, faster is better and I'm sure this makes things faster.
Oh and can we talk about how broken it was that Java 6 and under had a fixed size pool for .intern()'d strings?
A typical web app runs against a database with a genetic query optimizer, on top of a VM with a concurrent generational GC, sharing virtual memory with a dozen other processes, arranged in a massive pyramid of caches, which are competing for CPU time from a multi-core monstrosity of a data-flow engine.
The sooner we as programmers embrace stochastic methods, the better.
Not so long ago I had to do maintenance on a pretty large Swing application, still stuck on Java 6, that was built around displaying huge amounts of data, holding it all in memory, after retrieving it from some rather slow web services. The poor thing easily ended up using about a couple of gigs, mostly due to the many Strings it held, many of them pretty repetitive. While I tried to reduce the memory footprint, I couldn't just intern everything coming from the service: In Java 6, interned strings come from PermGen.
Using a hashmap to allocate everything would have been better than nothing, but the dataset had a whole lot of strings that didn't repeat themselves, so the hashmap would have been far bigger than we needed for the application.
What I ended up having to do what to figure out where the data was the most repetitive, and then intern only those strings.
I cut memory use by over 30%, but it took days of profiling, evaluating the data and making simple code changes to get there, as opposed to just a runtime flag. Now, I wonder how much better, or worse, it performs that the hashmap solution in cases like the one I faced: a few hundred strings repeated tens of thousands of times, and hundreds of thousands of strings with almost no repetition.
Thankfully Java tooling is fairly mature - things like MAT and OQL were of great use in finding the memory hogs and leaks.
With a little bit of magic, C compilers and linkers are even allowed to turn (simplified example)
const char s1[] = "some string";
const char s2[] = "string";
into const char s1[] = "some string";
const char s2[] = s1+5;
and place these constants in a read-only section shared between multiple loaded instances of the same library or program.> Taking the above into account, the actual expected benefit ends up at around 10% heap reduction. Note that this number is a calculated average based on a wide range of applications. The heap reduction for a specific application could vary significantly both up and down.
But in my team alone, we have services which deal with many equal but transient strings, some services with long-living, mostly equal strings, some services with long-living, radically different strings. In some of them, I expect rather massive reductions, in others, interning probably has most of the work done already and in others, there's no application or the GC will handle the issue already.
http://www.boost.org/doc/libs/1_56_0/libs/flyweight/doc/inde...
Edit: changed avoid deduplication to avoid duplication
No love for hashset?
Will benchmark that application with +UseStringDeduplication
> In fact the String Deduplication is almost like interning with the exception that interning reuses the whole String instance, not just the char array.
Interning reuses whole String instances. Deduplication is like interning with the exception that it does not reuse the whole String instance, it just reuses the char array. Therefore surely deduplication does not reuse String instances.