Selectively Shifting and Constraining Computation
David Lloyd
david.lloyd at redhat.com
Tue Oct 25 14:04:28 UTC 2022
On Mon, Oct 24, 2022 at 9:40 PM John Rose <john.r.rose at oracle.com> wrote:
>
> On 24 Oct 2022, at 19:06, David Lloyd wrote:
>
> > On Mon, Oct 24, 2022 at 7:39 PM John Rose <john.r.rose at oracle.com> wrote:
> >
> >> On 21 Oct 2022, at 22:56, forax at univ-mlv.fr wrote:
> >>
> >>> I'm a great fan of the lazy statics, but you do not only get reordering
> >> of the side effects, you may also get double executions of the
> >> initialization code, double executions of the side effects.
> >>> So the constraint on the side effects when initializing a lazy static is
> >> quite radical, do not do them .
> >>
> >> I think you are referring to the draft semantics of lazies which
> >> piggy-back on top of CONSTANT_Dynamic, which indeed allows initialization
> >> races and therefore double side effects. I’m getting rid of this in the
> >> newest draft of the JEP, so that refactoring to lazy will be easier to say
> >> “yes” to.
> >>
> >> A lazy static should never double its initializer, regardless of
> >> init-races. My current plan is to insist that the same class locking be
> >> done for each lazy init as for <clinit> itself (which is the big lazy init
> >> of the overall class). And on the same CL object mentioned in JVMS 5.5.
> >>
> >
> > Wouldn't it be preferable to use a lock per lazy static?
>
> In short, probably not. You’d have lots of extra footprint (all those monitor states) for no demonstrable gain.
Wouldn't the monitor only actually be necessary during the actual
initialization? Otherwise the number of initialization states per
field would be identical, I would expect. Since lazy static
initialization would be "rare", I would therefore expect the monitor
(or its equivalent) to be stored out-of-line with respect to the
semi-permanent class structures, and only retained until
initialization is complete, whereas when the init lock LC is shared,
it must be created no later than the first initialization event and
destroyed no sooner than after every field and the class itself have
been initialized.
> (…Despite the speculations you made, which I also made but w/o coming to any definite benefit.)
The avoidance of deadlock is a definite benefit IMO :-). Class init
deadlocks have historically existed in the wild. Since the invisible
class initialization lock also is coupled to the class inheritance
initialization sequence (super before sub), the same kinds of
dependencies which can cause class init deadlocks could cause lazy
static deadlocks, except it might be less clear what is happening, and
why, due to the independent initialization of the lazy statics
themselves.
And, since it seems I owe you some speculation: concurrent
initialization can have performance benefits as well, relating to
startup time. I also speculate that fully independent initialization
would have benefits for native image generators of the present and
future.
> You’d lose something too: The sequencing of initialization (lazy and not-lazy) of a single class would lose coherence. This IMO is a risk: The more lazies differ from not-lazies, the more possibility of bugs when adopting lazies. And allowing a class to run initialization expressions concurrently is surely much less compatible with the current state, where initialization expressions are run in sequence.
I would argue that independently-locked lazies would be _less_
different from not-lazies because the thing that lazy statics is
really replacing, AFAICT, is the "lazy holder" pattern, much in the
same way that lambdas replace many usages of anonymous classes. Giving
them independent locks is, from this perspective, less different from
the status quo than sharing a lock.
--
- DML • he/him
More information about the leyden-dev
mailing list