4 ms·
I'm not sure if this is the case for the JVM, but for .NET it is perfectly legal for the VM to store the object address somewhere after allocation but prior to
by johncolanduoni 9y ago
I'm not sure if this is the case for the JVM, but for .NET it is perfectly legal for the VM to store the object address somewhere after allocation but prior to the constructor running/becoming visible. All of the fields objects will be zeroed so this won't cause memory unsafety, but it's rarely what you expect to happen.
Forgetting this is a big source of bugs in double checked locking in .NET.
- MichaelGG 9y agoIt could cause other correctness issues that could break CAS, for instance (which yeah seems like a poor idea in hindsight since it's so complicated). If this is actually allowed it seems like a huge mistake in the .NET memory model. I've never seen a definitive answer on it (not saying you're wrong).
- aardvark179 9y agoIt has to be legal for the VM to store the object before it has been entirely initialised, but the question is whether other threads will be able to see it in that uninitialised state. If other threads can see a partially initialised object then you remove most of the nice guarantees final fields give the JIT. NB. You can break all the JMM guarantees by having the constructor share the object reference with another thread. The JMM even says: > If a reference to an object is shared with other threads during the initial construction of an object, most of the guarantees for final fields of that object can go kerflooey; this includes cases in which other parts of a program continue to use the original value of this field.
- MichaelGG 9y agoIf you do it from the constructor (assign this to a shared field) then that seems acceptable and narrows the scope of issues a ton. Do you know of a definitive answer on this by an actual team member with citations? I've seen well respected community people assert that partially constructed objects can be visible but that seems wrong. I would expect this to have practical memory safety issues: somewhere in the standard libraries there have to be interoperability classes that could result in unsafe access if partially constructed.
- aardvark179 9y agoThe safety guarantees only apply to final fields, it's entirely possible to see non-final fields in a half initialized state, and even half written longs because the memory model does not guarantee those operations are atomic. To be safe in those cases you must use synchronization or something else that establishes a happens before relationship. I think there's some good talks on the JMM on YouTube, and stuff on Shipilev"s blog.
- jmull 9y agoThat seems like a bad thing. I'd think that you'd want your language to guarantee an initializer has completed before letting an object/structure/whatever be visible. At least as the default. I mean, that doesn't even give an object a chance to initialize a synchronization mechanism before it's thrown into the wild where it needs one. It sounds like initializing fields to zero is guaranteed, but is that flexible enough to generally base synchronization on?
- johncolanduoni 9y agoIt's a performance trade off, because in general it's hard for the compiler to know whether it needs to insert a memory barrier or not if you do something like: this.fooField = new Something() which would need a memory barrier if another thread is expected to access fooField concurrently, and not need one otherwise. Putting memory barriers on every field assignment of a constructed object would be pretty expensive. It's also worth noting there's not anything that special about constructors here; there's a million other ways you can get similar issues when you try to handle concurrency at this level. For example if you do: this.bar.changeSomeFields() this.fooField = this.bar and changeSomeFields doesn't invoke a memory barrier at the right time you'll get the same problem if fooField isn't volatile.
- jmull 9y agoYes, I guess it is reasonable. Come to think of it, I objected because I thought it doesn't give you a chance to initialize whatever your object/structure/whatever's synchronization mechanism is. But that's not really true. The call to initialize your synchronization mechanism would contain the barrier you need so a general initialization doesn't generally need one.
- lostmsu 9y agoI doubt that statement is correct.
- johncolanduoni 9y agoIt is, Jon Skeet (as usual) has a great blog post on it that even discusses Java: http://csharpindepth.com/Articles/General/Singleton.aspx http://csharpindepth.com/Articles/General/Singleton.aspx Specifically the "third version" exposes the object before the effects of construction are necessarily visible on other threads.
- juancn 9y agoJava is the same, but final fields are special. The object cannot be published until they're completely initialized (unless the constructor unsafely publishes them).