--
guava-...@googlegroups.com
Project site: http://guava-libraries.googlecode.com
This group: http://groups.google.com/group/guava-discuss
This list is for general discussion.
To report an issue: http://code.google.com/p/guava-libraries/issues/entry
To get help: http://stackoverflow.com/questions/ask (use the tag "guava")
Unless one can provide the complete contents of the Immutable when it is first created, you need both a Builder and the Immutable itself.
I would strongly recommend against a constructor that simply receives
a list without copying. Copying is the sine qua non here for the
immutability guarantee
> Considering that the Builder objects are almost always local to a singleEscape analysis works like this:
method, and their structure and methods typically simple, I'd expect
current VMs (at "server"/ C2 opt level) to stack-allocate the builders
trough escape analysis. This should give use the best of two worlds,
at least in hot code that gets full optimization.
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis
It won't allocate objects on the stack, but it might skip unnecessary
instantiations.
However, this will never really work for builders: The builder
instance might be optimized away, but I doubt the jvm will ever be
able to remove non-fixed array or unlimited linked allocations.
Escape analysis is very useful to eliminate synchronized and to allow
for a more carefree instantiations of lightweigt wrappers and such.
Especially for scala, whose implicit conversions will likely always be
optimized away. :-)
True that it doesn't work now; but certainly not true that it can never work. Right now the JVM is not able to fully deconstruct builders--in part because these have some overhead that could be eliminated: indirection from ArrayList backing store; defensive copy to create the final immutable list that could be avoided with a hand-off protocol.
True that it doesn't work now; but certainly not true that it can never work. Right now the JVM is not able to fully deconstruct builders--in part because these have some overhead that could be eliminated: indirection from ArrayList backing store; defensive copy to create the final immutable list that could be avoided with a hand-off protocol.There's always going to be some copying in the build() methods. Two reasons:
- The array backing the builder usually won't match the exact size of the result, and we don't want or need that extra space.
- Builders can be reused.
I'd be curious to see the change you were experimenting with, though.
- The array backing the builder usually won't match the exact size of the result, and we don't want or need that extra space.
This is true in the general case for common collections, but not for immutable collections. Immutability implies having all the input data at construction time; so you usually know the amount of data. And if you know that, then you can preallocate the builder with the exact space it needs for those elements. Of course there's always the odd case where this preallocation is not possible or inefficient, e.g. when consuming an InputStream, or when populating the builder with a complex algorithm. But these are rare exceptions, at least my experience with Guava is that I can preallocate >95% of all immutable collections.
Also worth notice, slack space is only a problem for long-lived collections, and not all immutable collections are long-lived. If you check for example the Java code produced by protoc (protocol buffer compiler), it doesn't care to trim the collections used by its builders; the final immutable message classes will often have unused capacity. But nobody cares because protobuf objects are typically used for persistence or remoting, so their lifecycle is usually requiest/transaction-scoped at best. Making an extra data copy to prevent temporary use of extra memory for a couple milliseconds doesn't make any sense.
Even if we want to be conservative and not make the API more complex with extra methods like a build(boolean trim), the building logic could easily copy the backing array only conditionally, when used size != capacity.
- The array backing the builder usually won't match the exact size of the result, and we don't want or need that extra space.
This is true in the general case for common collections, but not for immutable collections. Immutability implies having all the input data at construction time; so you usually know the amount of data. And if you know that, then you can preallocate the builder with the exact space it needs for those elements. Of course there's always the odd case where this preallocation is not possible or inefficient, e.g. when consuming an InputStream, or when populating the builder with a complex algorithm. But these are rare exceptions, at least my experience with Guava is that I can preallocate >95% of all immutable collections.
Also worth notice, slack space is only a problem for long-lived collections,
and not all immutable collections are long-lived.
One of the most common uses I have for immutable maps is to hold long-lived indexes that are initialized from some stream (whose size I can't predict). I'm happy for a Builder to over-allocate during initialization, but I don't want that over-allocation to last past the call to build().
- The array backing the builder usually won't match the exact size of the result, and we don't want or need that extra space.
This is true in the general case for common collections, but not for immutable collections. Immutability implies having all the input data at construction time; so you usually know the amount of data. And if you know that, then you can preallocate the builder with the exact space it needs for those elements. Of course there's always the odd case where this preallocation is not possible or inefficient, e.g. when consuming an InputStream, or when populating the builder with a complex algorithm. But these are rare exceptions, at least my experience with Guava is that I can preallocate >95% of all immutable collections.I'm not sure we're talking about the same thing. Builders don't know how many elements they'll have when build() gets called. Their internal arrays have to have room for added elements.
Also worth notice, slack space is only a problem for long-lived collections, and not all immutable collections are long-lived. If you check for example the Java code produced by protoc (protocol buffer compiler), it doesn't care to trim the collections used by its builders; the final immutable message classes will often have unused capacity. But nobody cares because protobuf objects are typically used for persistence or remoting, so their lifecycle is usually requiest/transaction-scoped at best. Making an extra data copy to prevent temporary use of extra memory for a couple milliseconds doesn't make any sense.Minimizing memory usage for immutable collections is unquestionably a priority for us. Even if they're not necessarily long-lived, they're used extremely widely across so many different services. Indeed, I think we're inclined to pay the price at construction time of the additional copy, in exchange for those memory savings.
Even if we want to be conservative and not make the API more complex with extra methods like a build(boolean trim), the building logic could easily copy the backing array only conditionally, when used size != capacity.But that said, builders can be reused. Just because build() gets called once doesn't mean that more elements won't be added and build() won't be called again.Additionally, the case that the backing array has exactly the right size is relatively rare, generally speaking.
On Thu, Apr 26, 2012 at 1:56 PM, Osvaldo Doederlein <opi...@google.com> wrote:
- The array backing the builder usually won't match the exact size of the result, and we don't want or need that extra space.
This is true in the general case for common collections, but not for immutable collections. Immutability implies having all the input data at construction time; so you usually know the amount of data. And if you know that, then you can preallocate the builder with the exact space it needs for those elements. Of course there's always the odd case where this preallocation is not possible or inefficient, e.g. when consuming an InputStream, or when populating the builder with a complex algorithm. But these are rare exceptions, at least my experience with Guava is that I can preallocate >95% of all immutable collections.It's precisely those cases for which I don't know the exact size of the collection in advance that I use Builders. It's not rare at all for me.
One of the most common uses I have for immutable maps is to hold long-lived indexes that are initialized from some stream (whose size I can't predict). I'm happy for a Builder to over-allocate during initialization, but I don't want that over-allocation to last past the call to build().