2009-12-01 6 views
9

que tienen el entendimiento de que el tamaño de la ondulación permanente se utiliza para almacenar los metadatos, que incluiría código de bytes, etc. estática cosas¿Cómo afecta la reflexión el tamaño de Permanente?

Mi pregunta ¿cómo el uso de la reflexión afecta al tamaño de la ondulación permanente, si es que lo hace. quiero decir que si Programa-A utiliza modo normal de funcionamiento y objetos Programa-B utiliza la reflexión de todo, ¿cómo va los Perm-tamaños de los dos programas de comparación de?

Respuesta

7

El espacio permanente crecerá cuando se ejecuta código que se carga nuevas clases o internalizar cadenas. Las clases de reflexión tienen que cargarse, eso es seguro. No estoy seguro si la API de reflexión utiliza cadenas internalizadas en gran medida, pero no debería ser difícil de averiguar.

Por ejemplo, para el método getDeclaredMethod(String name, Class<?>... parameterTypes) el parámetro del nombre se internalizará.

Este fragmento se llena muy bien el espacio permanente:

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

En una aplicación real no hará ninguna diferencia.

+0

Lo que creo que está viendo es que se ha introducido el nombre buscado para que '==' se pueda utilizar en los nombres de métodos ya internados. (No estoy convencido de que sea una gran idea.) De cara, la reflexión puede crear clases (a veces). –

+0

(Las cadenas internas son GCable con un ciclo completo de recolección de basura, asume una buena calidad de implementación). –

+0

@Tom, ¿puedes dar un ejemplo único donde se crea una clase por reflexión? No estoy tratando de ser un dolor, realmente me gustaría saber de estos casos ya que nunca he visto uno. – PSpeed

3

No estoy del todo seguro de entender la pregunta, pero las clases de Java ya incluyen todo lo necesario para realizar una reflexión sobre ellas. Un archivo .class no cambia en función de cómo se usa.

Edición 1: Proporcionando algunos ejemplos más específicos para distinguir mejor el tipo de "reflexión" de la que estamos hablando.

Ejemplo:

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);  

En el caso de llamada convencional, Foo.class y cualquiera de sus dependencias de clase directa se cargará. la barra se ejecutará. Las cadenas "Foo" y "bar" ya se han internado como parte de la clase de llamada porque el código de bytes utiliza cadenas para resolver las clases y métodos en tiempo de ejecución. (en realidad, "barra" será la firma de método completa, por lo que en realidad es más larga que solo "barra")

En el caso de reflexión, sucede exactamente lo mismo. La única clase adicional cargada es Method.class. Ese debería ser el único efecto en el tamaño de la permanente.

El último caso tiene implicaciones de rendimiento. La búsqueda de métodos es relativamente cara, por lo que es aconsejable guardar en caché los objetos de Method cuando pueda. La invocación de método adicional para invocar tiene una pequeña implicación de rendimiento, ya que se trata de una llamada de método adicional. El punto de acceso tendrá problemas para optimizar a través de esta llamada ... al menos más de lo normal. JITing sucede exactamente lo mismo.

Edición 2: Observando algunos objetos adicionales que se cargan durante la reflexión ...

java.lang.Class creará y método de objetos de caché (u objetos de campo, etc.) en el momento de acceso. Se almacenan en caché en SoftReference y, por lo tanto, se recuperarán si el uso de memoria lo requiere.

Sin embargo, la inicialización de estos objetos significa que puede haber cadenas adicionales internados cargadas por la VM para admitir la creación de estos objetos de Método. Supongo que es probable que estas cadenas ya formen parte del grupo constante de la clase reflexiva, pero es posible que no lo sean. De cualquier manera, es un golpe de tiempo único por método por clase, por campo por clase, etc. Acceda a los métodos, obtendrá al menos todos los nombres de los métodos internados. Acceda a los campos, obtendrá los nombres de esos campos internados.

+0

Las clases pueden generarse dinámicamente mediante la implementación de reflexión para un acceso rápido. –

+0

Referencia por favor? Uso el reflejo todo el tiempo (realmente ... todo el tiempo) y nunca he visto una clase generada como resultado. Las bibliotecas de terceros pueden hacer algunas cosas y las cosas de proxy dinámico definitivamente generarán una clase de tiempo de ejecución. Pero simplemente llamar a métodos en una Clase/Objeto no debería. – PSpeed

+0

@ PSpeed..pls compruebe el siguiente enlace https://jaxb.dev.java.net/issues/show_bug.cgi?id=581 –

2

La primera respuesta es básicamente correcta: si una clase se carga 'normalmente' o mediante reflexión, no hay diferencia. De cualquier manera, está cargado. No puedo pensar en ninguna diferencia en cadenas internas que sepa.

Supongo que hay un efecto más indirecto: al usar la reflexión, es posible que se carguen menos clases. Digamos que tienes un código que carga una de 100 clases basadas en algún parámetro. Escríbelo sin reflexión, importaría las 100 clases y crearía una instancia de una de ellas.

Con reflexión, solo se cargará 1 clase. Sin, en el momento en que se carga la clase con este código, las 100 clases importadas se cargarían ya que todas están referenciadas. Entonces, se cargan más clases en el espacio permanente.

Pero este es un ejemplo algo artificial. A menos que describa realmente su situación, imagino que prácticamente no notará ninguna diferencia. Es decir, hasta que esté seguro de que no es trivial, no permita que esto influya en sus decisiones de diseño.

3

La reflexión puede generar clases, dependiendo de la implementación. Puede, por ejemplo, necesitar usar un artefacto de reflexión miles de veces antes de compilarlo en bytecode.

Como siempre, el consejo es: Perfile su código en situaciones realistas.

+0

¿Te refieres a "código nativo" arriba? Las clases ya son código byte. El punto de acceso tendrá problemas para optimizar a través de llamadas de reflexión, pero el JIT se comporta de la misma manera. – PSpeed

+0

No, me refiero a bytecode. Obviamente, después del uso, HotSpot compilará el código de bytes como nativo. Los campos se pueden leer al encontrar el desplazamiento desde el inicio del objeto y agregarlo. También se pueden leer escribiendo el código de bytes que lee esos campos (que ignora los privilegios de acceso). Algo así continúa (en el Sun JRE), pero me olvido de los detalles. –

+0

+1: Simplemente active el registro de GC y compruebe System.out - [Clase de descarga sun.reflect.GeneratedMethodAccessor1403] [Clase de descarga sun.reflect.GeneratedConstructorAccessor446] [Clase de descarga sun.reflect.GeneratedMethodAccessor562] - Estos son generados por el reflejo implementación. – fglez

Cuestiones relacionadas