mercredi 6 février 2013

ORA-04031: KGLH0 grossit de manière excessive

Sur une instance Oracle 11.2.0.2, j'ai rencontré dernièrement des problèmes sur une partie du shared pool, KGLH0.

Dans un premier temps, on m'a rapporté des arrêts répétés de l'instance inexpliqués, un startup de l'instance permettant de contourner le problème ... jusqu'au prochain arrêt. Au bout d'un certain nombre d'arrêt/relance, j'ai été voir les incidents de l'instance via adrci ( show incident ). On pouvait alors constater quelques incidents générant des erreurs ORA-4031.  Puis, en consultant le fichier trace ( show incident -mode detail -p "incident_id=xxxx" ) , on pouvait observer une allocation mémoire excessive de la KGLH0.

En consultant le support Oracle, le bug ID 1351675.1 décrit bien le problème observé. Sur l'instance en question, en utilisant la requête : select name, bytes from v$sgastat  where pool= 'shared pool' and name = 'KGLH0' , on s'aperçoit qu'au démarrage de l'instance, cette zone est initialisée à environ 12  MB, mais elle est susceptible de monter à plus de 300 MB dans certains cas, puis si l'instance n'est pas arrêtée, elle tombe en émettant plusieurs erreurs ORA-4031.

Si comme dans notre cas de figure, vous n'avez pas la possibilité de patcher l'instance, il ne vous reste plus qu'à écrire une procédure stockée vidant le shared pool ( alter system flush shared_pool ), cette dernière étant lancée par un job oracle. Mais comme l'indique la note du support, cela n'a pas suffi, et dans certains cas, la zone ne se désalloue pas.

Pour éviter de perturber les tests effectués sur cette instance, j'ai fini par me résoudre à faire un arrêt/relance de l'instance chaque soir via la crontab.

Ajout:
Quelques semaines plus tard, l'instance est de nouveau tombée. J'ai dû me résigner à augmenter le shared pool via le paramètre MEMORY_TARGET. Pour le flush du shared pool, j'ai omis de dire qu'il ne se déclenche qu'à partir d'un seuil ( 5% de la MEMORY_TARGET ), choix effectué après avoir observé plusieurs pics KGLH0.

La table X$KSMSP ( à ne pas utiliser en production ) contient la liste des différentes parties ( chunks ) du shared pool. Si vous souhaitez avoir une vision fine du shared pool, je vous conseille le chapitre 7 du dernier livre de J.Lewis et plus particulièrement le paragraphe sur les structures du shared pool.

En utilisant cette table durant un test, on peut observer les choses suivantes:

SQL> r
  1* SELECT KSMCHCLS CLASS, COUNT(KSMCHCLS) NUM, SUM(KSMCHSIZ) SIZ, To_char( ((SUM(KSMCHSIZ)/COUNT(KSMCHCLS)/1024)),'999,999.00')||'k' "AVG SIZE", sysdate FROM X$KSMSP GROUP BY KSMCHCLS

CLASS           NUM            SIZ    AVG SIZE     SYSDATE
-------- ---------- ---------- ------------ ---------
R-freea           268           22048          .08k  18-JAN-13
freeabl     74600 265871184      3.48k  18-JAN-13
recr         22646   48520808      2.09k  18-JAN-13
R-free             133      49402056    362.74k  18-JAN-13
R-recr                1         3977192 3,883.98k  18-JAN-13
R-perm            15       38615608  2,514.04k  18-JAN-13
free              4092    165599832       39.52k  18-JAN-13
perm                67    111648480   1,627.34k  18-JAN-13

8 rows selected.

SQL> shutdown abort; => pas très propre, mais c'est un test !
ORACLE instance shut down.
SQL> startup force;
ORACLE instance started.

Total System Global Area 1068937216 bytes
Fixed Size                  2226472 bytes
Variable Size             973080280 bytes
Database Buffers           88080384 bytes
Redo Buffers                5550080 bytes
Database mounted.
Database opened.
SQL> SELECT KSMCHCLS CLASS, COUNT(KSMCHCLS) NUM, SUM(KSMCHSIZ) SIZ, To_char( ((SUM(KSMCHSIZ)/COUNT(KSMCHCLS)/1024)),'999,999.00')||'k' "AVG SIZE", sysdate FROM X$KSMSP GROUP BY KSMCHCLS;

CLASS           NUM        SIZ AVG     SIZE     SYSDATE
-------- ---------- ---------- ------------ ---------
R-freea             110          5280          .05k   18-JAN-13
freeabl        6575 17252784      2.56k  18-JAN-13
recr            9755 16840120       1.69k 18-JAN-13
R-free                55    37689072    669.20k 18-JAN-13
R-recr                 1      3977192   3,883.98k 18-JAN-13
R-perm             17     41701472   2,395.53k 18-JAN-13
free                  75       9716312      126.51k 18-JAN-13
perm                80   103499648   1,263.42k 18-JAN-13

8 rows selected.

Un peu plus tard :

SQL> SELECT KSMCHCLS CLASS, COUNT(KSMCHCLS) NUM, SUM(KSMCHSIZ) SIZ, To_char( ((SUM(KSMCHSIZ)/COUNT(KSMCHCLS)/1024)),'999,999.00')||'k' "AVG SIZE", sysdate FROM X$KSMSP GROUP BY KSMCHCLS;

CLASS           NUM        SIZ AVG            SIZE     SYSDATE
-------- ---------- ---------- ------------ ---------
R-freea              184              8832            .05k   18-JAN-13
freeabl       38200  117867568        3.01k  18-JAN-13
recr           38144    67380752        1.73k  18-JAN-13
R-free                 92       45562968       483.64k  18-JAN-13
R-recr                  1          3977192    3,883.98k  18-JAN-13
R-perm              17        41701472     2,395.53k 18-JAN-13
free                 579          5869440             9.90k 18-JAN-13
perm                 80      103499648       1,263.42k 18-JAN-13

8 rows selected.

=> alter system flush shared_pool;

CLASS           NUM        SIZ AVG          SIZE     SYSDATE
-------- ---------- ---------- ------------ ---------
R-freea              184             8832            .05k  18-JAN-13
freeabl       24286   76702584        3.08k 18-JAN-13
recr            20384   35864800        1.72k 18-JAN-13
R-free                   92     45562968       483.64k 18-JAN-13
R-recr                    1        3977192    3,883.98k 18-JAN-13
R-perm                17       41701472    2,395.53k 18-JAN-13
free                  1508      78550376         50.87k 18-JAN-13
perm                    80    103499648    1,263.42k 18-JAN-13

Par ailleurs, on peut effectuer un dump mémoire du shared pool ( oradebug dump heapdump 2, voir pdf de M.Modrakovic ) pour observer de nombreux chunks relatifs à KGLH0:

Chunk  700000036fde000 sz=     4096    freeable  "KGLH0^8df877b8 "  ds=70000007d124330
  Chunk  700000036fdf000 sz=     4096    freeable  "KGLH0^8df877b8 "  ds=70000007d124330
  Chunk  700000036fe0000 sz=     4096    freeable  "KGLH0^8df877b8 "  ds=70000007d124330
  Chunk  700000036fe1000 sz=     4096    freeable  "KGLH0^8df877b8 "  ds=70000007d124330
  Chunk  700000036fe2000 sz=     4096    freeable  "KGLH0^8df877b8 "  ds=70000007d124330
  Chunk  700000036fe3000 sz=     4096    freeable  "KGLH0^8df877b8 "  ds=70000007d124330
  Chunk  700000036fe4000 sz=     4096    recreate  "KGLH0^8df877b8 "  latch=0
     ds  70000007d124330 sz=    28672 ct=        7
         700000036fde000 sz=     4096
         700000036fdf000 sz=     4096
         700000036fe0000 sz=     4096
         700000036fe1000 sz=     4096
         700000036fe2000 sz=     4096
         700000036fe3000 sz=     4096