Can't instantiate anonymous class more than 16 times

Rémi Forax forax at univ-mlv.fr
Tue Aug 11 15:05:21 PDT 2009


Le 11/08/2009 23:14, Wei Yin Teo a écrit :
> I tried both: true and false. :)
>
> In fact, setting it to true would fail the first time. In 
> ReflectionFactory.newConstructorAccessor, we have
>
> if (noInflation) {
> return new MethodAccessorGenerator().
>                 generateConstructor(c.getDeclaringClass(),
>                                     c.getParameterTypes(),
>                                     c.getExceptionTypes(),
>                                     c.getModifiers());
>         } else {
>             NativeConstructorAccessorImpl acc =
> new NativeConstructorAccessorImpl(c);
>             DelegatingConstructorAccessorImpl res =
> new DelegatingConstructorAccessorImpl(acc);
>             acc.setParent(res);
> return res;
>         }
>
> We get the generated bytecode constructor the first time instead when 
> the threshold is exceeded.


I see two other solution, you can bump the threshold to Integer.MAX_VALUE
or use this gory hack :)

     Constructor<?> constructor = 
testClass.getConstructor((Class<?>[])null);
     constructor.newInstance(); // Initialize accessor which is lazily 
created
     Field constructorPrimaryAccessorField = 
Constructor.class.getDeclaredField("constructorAccessor");
     constructorPrimaryAccessorField.setAccessible(true);
     Object constructorPrimaryAccessor = 
constructorPrimaryAccessorField.get(constructor);

     // traverse delegate
     Field delegateField = 
constructorPrimaryAccessor.getClass().getDeclaredField("delegate");
     delegateField.setAccessible(true);
     Object nativeAccessor = delegateField.get(constructorPrimaryAccessor);

     Field counterField = 
nativeAccessor.getClass().getDeclaredField("numInvocations");
     counterField.setAccessible(true);

     for (int i = 0; i < 100; i++) {
       try {
          constructor.newInstance();

         // reset counter
         counterField.setInt(nativeAccessor, 0);
       }
       catch(Throwable e) {
         ...


Rémi

>
>
> On 11 Aug 2009, at 21:47, Rémi Forax wrote:
>
>> Le 11/08/2009 21:03, Wei Yin Teo a écrit :
>>>
>>>
>>> On 11 Aug 2009, at 02:09, Rémi Forax wrote:
>>>
>>>> Le 11/08/2009 00:49, Wei Yin Teo a écrit :
>>>>> Right, I think the work around is working because we are getting a 
>>>>> new class and we don't hit the threshold.
>>>>>
>>>>> The magic number 15 is the ReflectionFactory.inflationThreshold() 
>>>>> as we can see in the class NativeConstructorAccessorImpl
>>>>>
>>>>>
>>>>> public Object newInstance(Object[] args) ...    {
>>>>> if (++numInvocations > ReflectionFactory.inflationThreshold()) {
>>>>>             ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
>>>>> new MethodAccessorGenerator().
>>>>>                     generateConstructor(...)
>>>>> ...
>>>>>
>>>>> I think the AnonymousClassLoader mangles the class name from 
>>>>> InstanceTest to InstanceTest/123456. However the generated 
>>>>> ConstructorAccessor would interpret that as a class 
>>>>> InstanceTest.123456 instead of InstanceTest and the JVM would then 
>>>>> try to load InstanceTest/123456.class. Of course it can't be found 
>>>>> anywhere. I suppose Class.forName() should not be able to locate 
>>>>> it in the system(permGen?) name space, either.
>>>>
>>>> You're right the problem is in package sun.reflect but the problem 
>>>> is not
>>>> a dot transformed to a slash or vice-versa.
>>>>
>>>> Class.forName() uses class loader mechanism, and anonymous class 
>>>> aren't registered
>>>> in any classloader cache. The reflection factory (here 
>>>> MethodAccessorGenerator)
>>>> generates a bytecode with the name of the anonymous class in the 
>>>> constant pool
>>>> to be able to call the constructor of the anonymous class.
>>>> When this bytecode is loaded, the VM tries to resolve it with a 
>>>> classloader mechanism,
>>>> so it fails throwing a NoClassDefFound.
>>>>
>>>> So, short time workaround:
>>>> use -Dsun.reflect.noInflation=false
>>>
>>> Apparently, this doesn't work as you can see the above 
>>> newInstance(..) calls 
>>> MethodAccessorGenerator().generateConstructor(...) when the 
>>> threshold is exceeded. Shouldn't it call 
>>> ReflectionFactory.newConstructorAccessor(), which is guarded by the 
>>> system property, instead?
>>
>> oup, sorry
>> -Dsun.reflect.noInflation=true
>>
>> Rémi
>> _______________________________________________
>> mlvm-dev mailing list
>> mlvm-dev at openjdk.java.net <mailto:mlvm-dev at openjdk.java.net>
>> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
>    

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20090812/6e6f62fc/attachment.html 


More information about the mlvm-dev mailing list