Bonjour,
Je suis en train de coder un cas d'étude pour provoquer une fuite mémoire, notamment en employant des variables statiques.
Pour mettre en évidence la cause de la fuite mémoire, je mets en confrontation 2 programmes (2 main() distincts), l'un qui alloue (indirectement) un gros objet statique, l'autre qui alloue (indirectement) un gros objet NON statique.
Je m'attends à ce que le premier plante.
Je m'attends à ce que le deuxième marche.
Or ce n'est pas le cas, ils plantent tous les deux pour problème de mémoire, je ne comprends pas pourquoi, pouvez-vous m'enseignez la théorie des dessous de la JVM.
Merci.
Le code :
Fichier FuiteMemoireAvecStaticMain.java
Fichier FuiteMemoireSansStaticMain .java
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package fr.memoryleak; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.util.List; /** * Augmente la valeur d'un compteur (version non static) */ public class FuiteMemoireAvecStaticMain { /** * @param args */ public static void main(String[] args) throws Exception { System.out.println("begin"); Compteur compteur = new Compteur(); RuntimeMXBean RuntimemxBean = ManagementFactory.getRuntimeMXBean(); List<String> arguments = RuntimemxBean.getInputArguments(); System.out.println("JVM running arguments : " + arguments); for (int i = 0; i < Integer.MAX_VALUE; i++) { compteur.incrementerCompteurAvecStatic(); System.gc(); } System.out.println("end"); } }
Fichier Compteur .java
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package fr.memoryleak; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.util.List; /** * Augmente la valeur d'un compteur (version non static) * */ public class FuiteMemoireSansStaticMain { public static void main(String[] args) throws Exception { System.out.println("begin"); Compteur compteur = new Compteur(); RuntimeMXBean RuntimemxBean = ManagementFactory.getRuntimeMXBean(); List<String> arguments = RuntimemxBean.getInputArguments(); System.out.println("JVM running arguments : " + arguments); for (int i = 0; i < Integer.MAX_VALUE; i++) { compteur.incrementerCompteurSansStatic(); System.gc(); } System.out.println("end"); } }
Fichier FuiteMemoire .java
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package fr.memoryleak; /** * Gestion d'un compteur * */ public class Compteur { private int valeurAvecStatic = 0; private int valeurSansStatic = 0; /** * Gestion d'un compteur (version static) */ public void incrementerCompteurAvecStatic() { FuiteMemoire fuiteMemoire = new FuiteMemoire(); fuiteMemoire.creerFuiteMemoireAvecStatic(); System.out.println("Valeur compteur : " + valeurAvecStatic++); } /** * Gestion d'un compteur (version non static) */ public void incrementerCompteurSansStatic() { FuiteMemoire fuiteMemoire = new FuiteMemoire(); fuiteMemoire.creerFuiteMemoireSansStatic(); System.out.println("Valeur compteur : " + valeurSansStatic++); } }
Sortie premier programme FuiteMemoireAvecStaticMain :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 package fr.memoryleak; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Classe responsable d'une fuite mémoire * */ public class FuiteMemoire { private static final int MAP_INIT_CAPACITY = 10; private static final int NON_STATIC_MAX_ELEMENT = (int) 4e4; private static final int STATIC_MAX_ELEMENT = (int) 1e4; private static List<Map<String, String>> staticMapList = new ArrayList<Map<String, String>>(); static { for (int i = 0; i < STATIC_MAX_ELEMENT; i++) { staticMapList.add(new HashMap<String, String>(MAP_INIT_CAPACITY)); } } private final List<Map<String, String>> nonStaticMapList = new ArrayList<Map<String, String>>(); /** * Creer une fuite memoire (version static) */ public void creerFuiteMemoireAvecStatic() { for (int i = 0; i < STATIC_MAX_ELEMENT; i++) { staticMapList.add(new HashMap<String, String>(MAP_INIT_CAPACITY)); } } /** * Creer une fuite memoire (version non static) */ public void creerFuiteMemoireSansStatic() { for (int i = 0; i < NON_STATIC_MAX_ELEMENT; i++) { nonStaticMapList.add(new HashMap<String, String>(MAP_INIT_CAPACITY)); } } }
Sortie deuxième programme FuiteMemoireSansStaticMain:begin
JVM running arguments : [-Xmx4m, -Dfile.encoding=Cp1252]
Valeur compteur : 0
Valeur compteur : 1
Valeur compteur : 2
Valeur compteur : 3
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
begin
JVM running arguments : [-Xmx4m, -Dfile.encoding=Cp1252]
Valeur compteur : 0
Valeur compteur : 1
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at fr.memoryleak.FuiteMemoire.creerFuiteMemoireSansStatic(FuiteMemoire.java:44)
at fr.memoryleak.Compteur.incrementerCompteurSansStatic(Compteur.java:27)
at fr.memoryleak.FuiteMemoireSansStaticMain.main(FuiteMemoireSansStaticMain.java:20)
Partager