reflection如何影响Perm的大小?

我理解perm大小用于存储元数据,包括字节代码,静态东西等。

我的问题是如何使用reflection影响烫发大小。 我的意思是如果Program-A使用正常的运行对象方式而Program-B全部使用reflection, 那么两个程序的perm大小将如何比较

当您执行将加载新类内化字符串的代码时,perm空间将增长。 必须加载reflection类,这是肯定的。 我不确定reflectionAPI是否确实使用了内部化的字符串,但它不应该很难找到。

例如,对于方法getDeclaredMethod(String name, Class... parameterTypes) ,name参数将被内化。

这个片段很好地填补了烫发空间:

 Random random = new Random(); while(true){ try { X.class.getDeclaredMethod(toBinaryString(random.nextLong())); } catch (Exception e) { } } 

alt text http://img4.imageshack.us/img4/9725/permgen.jpg

在现实世界的应用程序中,它将没有任何区别。

reflection可以生成类,具体取决于实现。 例如,在编译为字节码之前,您可能需要使用reflection工件数千次。

与以往一样,建议是:在实际情况下描述您的代码。

我不完全确定我理解这个问题,但Java类已经包含了对它们进行reflection所需的一切。 .class文件不会根据其使用方式而改变。

编辑1:提供一些更具体的例子,以更好地区分我们正在讨论的“反思”类型。

例:

 class Foo { public void bar() { System.out.println( "Hello, world." ); } } // Conventional calling Foo f = new Foo(); foo.bar(); // Reflection based callling Class fooClass = Class.forName( "Foo" ); Method m = fooClass.getMethod( "bar", null ); Object f = fooClass.newInstance(); m.invoke( m, null ); 

在传统的调用情况下,将加载Foo.class及其任何直接类依赖项。 酒吧将被执行。 字符串“Foo”和“bar”已经作为调用类的一部分被实现,因为字节代码在运行时使用字符串来解析类和方法。 (实际上“bar”将是完整的方法签名,所以实际上比“bar”更长)

在反思案例中,完全相同的事情发生了。 加载的唯一附加类是Method.class。 这应该是对烫发尺寸的唯一影响。

后一种情况具有性能影响。 方法查找相对昂贵,因此建议尽可能缓存Method对象。 对调用的额外方法调用具有轻微的性能影响,因为它是一个额外的方法调用。 通过此次通话,热点将难以优化……至少比正常情况更多。 JITing完全相同。

编辑2:注意在reflection期间加载的一些其他对象…

java.lang.Class将在访问时创建和缓存Method对象(或Field对象等)。 这些缓存在SoftReference中,因此如果内存使用需要它将被回收。

但是,这些对象的初始化意味着VM可能会加载其他内部字符串,以支持创建这些Method对象。 我的猜测是这些字符串可能已经是reflection类常量池的一部分,但它们可能不是。 无论哪种方式,每个类每个方法,每个类每个字段等一次点击。访问方法,你将至少获得这些方法的所有名称。 访问这些字段,您将获得这些字段的名称。

第一个答案基本上是正确的 – 一个类是否正常加载或通过reflection加载没有区别。 无论哪种方式,它都被加载了。 我不知道我所知道的实习字符串有什么不同。

我想有一个更间接的影响:使用reflection,你可能会导致更少的类加载。 假设您有一些代码根据某些参数加载100个类中的一个。 在没有reflection的情况下编写它,您将导入所有100个类并实例化其中一个类。

使用reflection,只会加载1个类。 如果没有,在加载此代码的类时,将加载所有100个导入的类,因为所有类都被引用。 因此,更多的类被加载到烫发空间。

但这是一个有点人为的例子。 除非它真的描述了你的情况,否则我想你几乎没有任何区别。 也就是说,直到你确定这不是微不足道的,不要让这影响你的设计决定。