Newsgroup: it.comp.java
Titolo: Allocazione di oggetti nel PermGen

Salve,
 
avrei un problema causato da una continua allocazione di memoria nel
PermGen.
 
Ho scritto un piccolo codice per monitorare la dimensione di tale spazio
di memoria e ho notato che quasi dopo ogni metodo invocato dai vari
oggetti della mia applicazione, la dimensione della memoria allocata
aumenta. Forse il problema è legato ad un'eccessiva presenza di oggetti
globali? C'è un modo per sapere quali sono gli oggetti effettivamente
presenti? Sarebbe utile conoscere il nome dell'oggetto, per adesso
riesco solo a calcolare la dimensione della memoria usata.
 
Il codice è il seguente, definito come un advice che scatta dopo
l'esecuzione di ogni metodo dell'applicazione:
 
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
 
import java.util.Iterator;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
 
 
@Aspect
public class PermGenStat {
 
	static Long bytesPrecedenti = getUsedPermGenBytes();
 
	private static Long getUsedPermGenBytes() {
 
		Long bytes = 0L;
 
		Iterator<MemoryPoolMXBean> iter =
ManagementFactory.getMemoryPoolMXBeans().iterator();
 
        while (iter.hasNext()) {
            MemoryPoolMXBean item = (MemoryPoolMXBean) iter.next();
            if (item.getName().equals("PS Perm Gen"))
            	bytes = item.getUsage().getUsed();
        }
 
        return bytes;
	}
 
	@AfterReturning (pointcut = "execution(* it.xxx.yyy.*.*.*.*(..))",
                     returning = "result")
 
	public void afterReturning (JoinPoint joinPoint, Object result) {
 
        if (joinPoint != null &&
        	joinPoint.getTarget() != null &&
        	joinPoint.getTarget().getClass() != null &&
        	joinPoint.getSignature() != null &&
        	joinPoint.getSignature().getName() != null) {
 
        	try {
        		Long bytes = getUsedPermGenBytes();
        	    Long diff = bytes - bytesPrecedenti;
 
        	    if (diff >= 1) {    
        	        System.out.println("Metodo: " +
joinPoint.getTarget().getClass().toString().substring(6) + "." +
 
joinPoint.getSignature().getName().toString());
 
        	        System.out.println("PermGen (KB): " +
Math.round((double)bytesPrecedenti / 1024) + " -> " +
 
Math.round((double)bytes / 1024) +
	        		                               " [" + Math.round((double)diff
/ 1024) + "]");
        	    }
        	    bytesPrecedenti = bytes;
		    }
            catch (Exception e) {
        	    System.out.println("******************** Eccezione
********************");
    	        System.out.println("Classe: PermGenStat - Metodo:
afterReturning");
    	        e.printStackTrace();
    	    }
        }
	}
}
 
Grazie
 
 

 riesco solo a calcolare la dimensione della memoria usata.
 
nello spazio di memoria permgen finiscono tipicamente le definizioni delle
classi ovvero gli oggetti Class<?> per intendersi. 
 
sempre tipicamente l'utilizzo di questa memoria aumenta nel momento in cui
vengono caricati in memoria i jar/class applicativi per poi andare a 
stabilizzarsi nel momento in cui tutte le classi necessarie sono in memoria.
 
si può avere un leak del permgen nel momento in cui si "gioca" con i 
classloader, per esempio scaricare e ricaricare le definizioni delle classi
dinamicamente come avviene nei redeploy degli application server tipo
tomcat. un altra possibilità di leak potrebbe essere quella di creare 
dinamicamente proxy (la libreria cglib è micidiale sotto questo punto di
vista). l'uso poco accorto di variabili static può essere concausa di questi
leak, ma sempre in subordine a una di queste modalità di operare. 
 
per tornare alla tua domanda l'indagine è tutt'altro che banale. esistono
strumenti come jmap e la jconsole che consentono di "navigare" la memoria
ma penso sia una impresa improba farlo senza avere idea di cosa si stia
cercando. solitamente si parte dalla causa primaria del leak come ad es. lo 
scaricamento di un classloader, e da lì indagare su cosa lo sta impedendo.
ma già così è una indagine molto frustrante.
 
in bocca al lupo.

 leak, ma sempre in subordine a una di queste modalitï¿œ di operare. 
 
In effetti l'applicazione viene deployata sia con tomcat che con jboss.
Credo che il problema sia legato al fatto che il progetto ï¿œ basato
framework Spring il quale fa un uso notevole di reflection.
 
Pensavo che ci fosse qualche opzione da passare alla JVM per far stampare
ad esempio il nome dell'oggetto che sta per essere allocato nel PermGen.
 
Grazie