prefacio
En primer lugar responder a la pregunta que se trate. Esto es principalmente debido a la presencia de un gran número de reflexiones generadas cargador de clases temporal y ASM clases generadas temporalmente serán retenidos en metaespacio, una vez metaespacio tiempo casi lleno, desencadenará FullGC, la recuperación ha alcanzado la clase ya no se usa el propósito del objeto. Por favor refiérase a las siguientes preguntas específicas de contenido, para lograr una mejor comprensión del principio de reflexión.
texto
contorno
Hay un sistema de gran capacidad de memoria (70G o más) antes de que la compañía ha estado utilizando CMS GC, sino porque el sistema es muy sensible al tiempo, porque gclocker en ocasiones conducen a destacar particularmente largo (aunque la adición de -XX: parámetros + CMSScavReengeBeforeRemark, pero gclocker que podrían causar observación el retraso YGC), no puede soportar una larga pausa tal tenía que pasar a la G1, después de una serie de melodía como relativamente estable, este parámetro será empujado a todas las máquinas en la
Pero la semana pasada, la máquina de repente apareció completa GC, G1 diseñada originalmente se esperaba completo GC no se produce, por lo general no es normal GC completo, registro de GC es el siguiente:
Desde el registro anterior no es difícil de encontrar debido a la ondulación permanente del gatillo completa GC, GC y después de la completa Perm a bajar, pero es necesario mencionar que JDK7 G1 normal de GC no les gusta de desinstalación, y sólo cuando está lleno GC será desinstalado, pero JDK8 se proporciona bajo los parámetros pertinentes que se puede hacer en la clase descargar algunas GC fase G1
Así que para la parte comercial de coredump hacer en primer lugar, guardar la escena y luego reiniciar el sistema y, a continuación, hizo un volcado de núcleo para la descarga del montón, pero no Heapdump 40G tan grande, se puede echar un vistazo a la forma en la ondulación permanente por jmap -permstat core.xxx Hay algo
Este artículo está relativamente largo, más relacionado con el conocimiento, si no se puede dejar de leer en, puede saltar a la última mirada a mi descripción del problema y luego girar a la lectura de este artículo le puede dar una visión más clara comprensión
¿Qué es exactamente rellena en Perm
Dado que es una permanente completa, entonces tenemos que ver Perm exactamente dónde poner lo que sabemos de Perm en la memoria principal es la clase de los datos en bruto, como el que carga una clase, y que la información de este tipo va a asignar memoria en Perm, donde a la tienda algunos de su estructura de datos, por lo que en la mayoría de los casos, la cantidad de Perm y el número de clases cargadas es una gran relación, por supuesto, en Perm ahorrará algunos otros datos en la versión inferior del tiempo, tal como String (String.intern () caso).
Además la experiencia nos dice que si se trata realmente de desbordamiento de Perm, esa posibilidad tendrá un lugar para construir un cargador carga dinámica de clases Una clase es grande, jmap con el comando anterior, podemos contar el número alcanzado realmente bajo sun.reflect.DelegatingClassLoader la 415 737
Puede ser básicamente bloqueado reflexivo cargador de clases de Perm causa desbordamiento, entonces ¿por qué hay tanto de lo que refleja el cargador de clases, lo que refleja lo que es el cargador de clases, luego decir brevemente que bajo el principio de la reflexión
principios reflejada
Como reflejo de todo el mundo es fácil de usar, ya que el rendimiento es bastante bueno, así que con bastante amplia, por lo que suelen utilizar la reflexión
método Método = XXX.class.getDeclaredMethod (xx, xx); method.invoke (objetivo, params)
Pero aquí no voy a utilizar una gran cantidad de código para describir su principio, pero decir algunas cosas claves, y luego juntos cuerdas
Obtener Método
Método de obtención de la primera llamada, adquirida por la lógica Método de las Clases de esta clase, y varios métodos y propiedades clave como sigue:
Hay en la clase en una propiedad clave llamada reflectionData, en el que el depósito principal se obtuvo de cada JVM, a algunos atributos de clase, como los métodos, campos, etc., es probablemente un largo camino
Esta propiedad es principalmente SoftReference, que es en algunos casos más exigentes de memoria es probable que ser reciclado, pero en circunstancias normales puede -XX: para controlar el momento de la recuperación de SoftRefLRUPolicyMSPerMB este parámetro, cuando se acabe el tiempo, siempre y cuando se producen GC será recuperar, y luego, después de que los medios de recuperación que existe una demanda de la hora de volver a crear uno de estos objetos, pero también es necesario tomar un pedazo de datos de la máquina virtual Java, y que la estructura de datos asociada Método, campo y otros campos se regeneran se objetos. objetos que puedan tener ningún problema si se vuelven a generado? Replicado de entender
getDeclaredMethod método es muy simple, consiste en copiar un objeto Método de la lista devuelta por el método privateGetDeclaredMethods a cambio. Y este proceso de copia se logra mediante searchMethods
Si reflectionData declaredMethods esta propiedad no está vacío, entonces regresar a sus privateGetDeclaredMethods directamente en él, de lo contrario ir a pescar uno de la JVM, y asignado al campo reflectionData, por lo que la próxima vez que puede llamar privateGetDeclaredMethods utilizan los datos almacenados en caché , no siempre ir a buscar los datos transferidos a la JVM, porque es reflectionData Softreference, por lo que existe el riesgo de obtener cualquier valor, teniendo al menos una vez antes de ir a pescar en la JVM
searchMethods de la lista de métodos de privateGetDeclaredMethods encontrar una manera de volver un partido del mismo nombre, y luego copiar un método objeto de la copia de la aplicación específica, de hecho Method.copy método:
Por lo tanto, Método de objetos cada vez que regresamos llamando a métodos getDeclaredMethod son, de hecho, un objeto nuevo, no es apropiado para ajustar Oh, si se llama a menudo la mejor caché. Pero este nuevo enfoque objeto tiene un atributo raíz apunta a un método reflectionData en la memoria caché, la memoria caché mientras su methodAccessor también se utiliza en ese método de methodAccessor.
las llamadas de método
Una vez que tenga Método, puede llamar a su método de invocación, a continuación, echar un vistazo a algunas informaciones clave Método
De hecho, la propiedad raíz se ha dicho más arriba, el punto principal para almacenar en caché el método objeto, que es, la corriente método objeto es en realidad construido de acuerdo con la raíz de este procedimiento, y por lo tanto la presencia de un Método Método raíz de múltiple deriva.
methodAccessor esto es clave, de hecho Method.invoke método es llamar al método de invocación methodAccessor, methodAccessor esta propiedad si la raíz en sí ha sido, sería vienen directamente de asignación methodAccessor de la raíz, de lo contrario se creará una
aplicación MethodAccessor
sí MethodAccessor es una interfaz
Hay tres realización principal
- DelegatingMethodAccessorImpl
- NativeMethodAccessorImpl
- GeneratedMethodAccessorXXX
DelegatingMethodAccessorImpl que es la inyección final de methodAccessor al método, que es un método de todas método de invocación será llamado a esta DelegatingMethodAccessorImpl.invoke, el mismo que su nombre, es el agente, que es la verdadera realización de lo siguiente puede ser dos especie
Si NativeMethodAccessorImpl, que sugiere su nombre, esto se logra principalmente nativa logra, y cada uno tiene que reflejarse GeneratedMethodAccessorXXX método invocado clase generada dinámicamente, después de un número XXX está en constante aumento y se reflejan ir todo el camino NativeMethodAccessorImpl, después de la melodía por defecto de 15 veces, genera una clase GeneratedMethodAccessorXXX, vamos a ir después de generar buena invocación de este método para generar clases de NativeMethodAccessorImpl forma que la transición a GeneratedMethodAccessorXXX él, echar un vistazo invocar el método NativeMethodAccessorImpl He dicho anteriormente, que es de 15 veces en las que ReflectionFactory.inflationThreshold () Este método devuelve, este 15 supuesto, no es su inmutable, que pueden ser especificados por -Dsun.reflect.inflationThreshold = xxx, también podemos -Dsun .reflect.noInflation = true para omitir el 15 NativeMethodAccessorImpl llaman lo anterior, y -Dsun.reflect.inflationThreshold = 0, el mismo efecto y GeneratedMethodAccessorXXX son, una vez después de que se crea para generar a través de nuevo MethodAccessorGenerator (). generateMethod conjunto de DelegatingMethodAccessorImpl desaparecido, por lo que la próxima Method.invoke será transferido a la recién creada MethodAccessor Lane.La generada GeneratedMethodAccessorXXX ve exactamente igual que él, este es probablemente el
De hecho, el método específico de llamar directamente al objeto de destino, y no hay diferencia entre las llamadas a métodos normalescargador de clases GeneratedMethodAccessorXXX
¿Qué carga GeneratedMethodAccessorXXX cargador de clases es que, después de generar un código de bytes buena llama al método siguiente para hacer la definición de clase
Así GeneratedMethodAccessorXXX cargador de clases es en realidad un cargador de clases DelegatingClassLoader
La razón para participar en un nuevo cargador de clases, por razones de rendimiento, y en algunos casos puede desinstalar estas clases generadas, debido a la descarga de la clase es sólo en el caso del cargador de clases pueden ser reciclados serán reciclados, si con el cargador de clases original que pueden causar estos clase recién creada no ha podido ser descargada desde el punto de vista del diseño en sí no queremos que tengan la memoria, cuando sea necesario allí en la línea existe en la memoria cuando esté apretada se puede liberar la memoria
cables de basura concurrentes a la creación de clases
Vea aquí no sé si has encontrado un problema, de hecho, no están por encima de NativeMethodAccessorImpl.invoke bloqueado ¿Qué significa? Si la hora de concurrente, también puede significar que hay muchos hilos para crear lógico clase entrar GeneratedMethodAccessorXXX, de hecho, aunque sólo habrá un uso final, pero estos costes no están ya en existencia, si hay 1.000 hilo han entrado en la lógica creada GeneratedMethodAccessorXXX de, que significa la creación de más de 999 clases no deseados habría sido ocupada la memoria, la GC se puede recuperar hasta que la recuperación se llevará a cabo en Perm
Eso es exactamente lo que los métodos están constantemente reflejarla
Una vez que haya reflejado en la cara de los principios del entendimiento, sabemos que después de un cierto número de veces que debe realizarse la reflexión, de hecho, va a construir una clase dinámica, en esta clase correspondiente a las llamadas a métodos del objeto de destino directamente, como hemos aprendido en el volcado del montón hay una gran cantidad de cargas DelegatingClassLoader cargador de clases de la clase GeneratedMethodAccessorXXX, y que al final estas clases se llama ¿qué métodos, por lo que tenemos que hacer una cosa, y que es la memoria de estas clases vierten hacia abajo, y luego hacer el código de bytes analizar una estadística
Volcado de código de bytes de clases en tiempo de ejecución
Podemos utilizar la interfaz SA de volcado de núcleo en curso o en vivo en el correspondiente abajo volcado clase, para volcar hacia abajo nuestra clase en particular, de primera clase escribimos un filtro
El uso de SA frasco ($ JAVA_HOME / lib / sa-jdi.jar) compilado después de clase, entonces llamamos al comando siguiente para volcar la clase compilada en el directorio
De manera que todos podemos GeneratedMethodAccessor para volcar hacia abajo, y esta vez sólo tendremos que mirar el código de bytes de una clase por javap -verbose GeneratedMethodAccessor9
Ver más arriba BCI clave de la línea 36, donde el método es el método que llamamos la reflexión, como por ejemplo el llamado método de reflexión anterior es org / Codehaus / Xfire / util / ParamReader.readCode
clases y métodos específicos objetivo reflectantes
Después de estos volcado código de bytes, que hacemos un byte de código de todos estos clase de estadísticas, a encontrar toda método llamado la reflexión, y luego encontrar alguna clase de modelo (paquete es el mismo) en realidad produce más de 20 diez mil clase, lo que significa que hay una gran cantidad de estas clases del modelo no reflexión
Con esta clave es cuidar el código exactamente donde habrá un reflejo lógico llamar a estos métodos de modelo, pero por desgracia no se encontró, pero este modelo es altamente probable que el objetivo en algunos casos, es el momento de deserialización RPC, la fiesta final está pidiendo Xfire uso de los servicios de negocio, y con la experiencia que han acumulado muchos años de marco de desarrollo, es determinar los objetos deserializar Xfire por medio de la reflexión, el código específico de la siguiente manera (org.codehaus.xfire.aegis.type.basic .BeanType.writeProperty): El JavaBean de PropertyDeor en el get / métodos set, de hecho, el propio envase es SoftReferenceVemos aquí tal vez todos lo entendemos, ha dicho antes que es posible recuperar GC SoftReference a cabo, el tiempo viene que se recuperará en la próxima GC, si se recuperó, tendría que volver a adquirir, a continuación, el equivalente de nuevo objeto método de invocación llamadas de método, las llamadas que más de un número, se tendrá que construir una nueva clase dinámica, y esta clase siempre será guardado en un GC hasta que pueda ser recuperado Perm
G1 recuperó Perm
Tenga en cuenta que bajo el sistema operativo utiliza G1 JDK7 y JDK7 el G1 a la ondulación permanente de hecho en circunstancias normales no se recicla, solamente se recuperará cuando se completa GC en Perm, lo que explica después de un número de G1 GC, Softreference se recuperarán esos objetos, pero no se recuperará la clase recién creada y, de hecho, por lo que el GC G1 más frecuentes, que significa que los objetos más probable SoftReference a ser recuperados (aunque en circunstancias normales es a tiempo, pero si no es con frecuencia GC , incluso si el tiempo se ha acabado, se quedará en la memoria de), más probabilidades de ser recuperado y que cuanto más fácil es producir una nueva clase hasta que se produzca la completa GC
soluciones
- La actualización a jdk8, se puede hacer la clase en proceso de descarga G1 GC
- Para una secuencia de protocolo, el método no tiene la reflexión, tal como arpillera
- SoftRefLRUPolicyMSPerMB ajustar este parámetro aumenta, pero esto no es una cura permanente
resumen
Lo anterior se relaciona con mucho, si no más que leer varias veces, puede ser difícil de hilar, voy a estar aquí esta situación se produjo más o menos describir el problema:
Este sistema utiliza JDK7 bajo G1, y esta versión de la G1 sólo lo hará la clase de Perm en el GC completa descargada en el momento del sistema debido a que un gran número de solicitudes que resulten en G1 GC sucede muy a menudo, pero el sistema también está configurado -XX : SoftRefLRUPolicyMSPerMB = 0, lo que significa SoftReference ciclo de vida no se mueve GC cruz, puede rápidamente recuperar perdido, hay una gran cantidad de llamadas RPC este sistema, caminando acuerdo Xfire para devolver los resultados hacen tiempo deserialización es ir lógica Method.invoke, y método asociado, por tanto, referencia SoftReference, que puede ser fácilmente reciclado, se recuperó una vez, sería crear un nuevo método objeto, a continuación, llamar a su método de invocación, después de una llamada a un número determinado de veces (15 veces) , para construir una nueva clase de código de bytes, junto con la realización de la GC, clase de código de bytes con un método de construcción de forma continua hasta que el gatillo Perm completa un GC completo era capaz de liberación
lectura recomendada
Una vez que el producto investigación 100% práctica optimización de la CPU
Hablar de una aplicación Java a partir de un caso real de optimización GC