mercredi 13 août 2008

EmptyWorkingSet

Bon alors il y a pas longtemps j'ai découvert un soft qui s'appelle Firefox Ultimate Optimizer qui permet de libérer la mémoire non utilisé par Firefox car comme beaucoup le savent dans le version 2.0 il y a pas mal de fuite de mémoire. D'après les dev de Mozilla plus de 350 sources de fuites de mémoire ont été corrigées dans la version 3.0. Donc c'est un soft très intéressant car il n'est pas rare que mon Firefox atteigne les 200Mo d'utilisation de mémoire et dès que je lance le soft il redescend entre 5 et 10Mo ( impressionnant n'est ce pas ). D'après Korben, tout l'intérêt du soft réside dans la fonction EmptyWorkingSet() qui fait tout le boulot mais comme il l'a dit il fallait y penser. Donc sans plus attendre je m'empresse d'aller trouver le secret de cette fonction ( moi qui suit un fana de ce genre de fonction avec surement un peu de mémoire virtuelle ) dans les sources de reactos.

BOOL STDCALL EmptyWorkingSet(HANDLE hProcess)
{
NTSTATUS nErrCode;
QUOTA_LIMITS qlProcessQuota;

/* query the working set */
nErrCode = NtQueryInformationProcess
(
hProcess,
ProcessQuotaLimits,
&qlProcessQuota,
sizeof(qlProcessQuota),
NULL
);

/* failure */
if(!NT_SUCCESS(nErrCode))
goto fail;

/* empty the working set */
qlProcessQuota.MinimumWorkingSetSize = -1;
qlProcessQuota.MaximumWorkingSetSize = -1;

/* set the working set */
nErrCode = NtSetInformationProcess
(
hProcess,
ProcessQuotaLimits,
&qlProcessQuota,
sizeof(qlProcessQuota)
);

/* success */
if(NT_SUCCESS(nErrCode))
return (TRUE);

fail:
/* failure */
SetLastError(RtlNtStatusToDosError(nErrCode));
return (FALSE);
}


Hum apparemment tout ce passe dans NtSetInformatioProcess avec un ProcessInformationClass à ProcessQuotaLimits, donc allons voir ça de plus près :


NTSTATUS
NTAPI
NtSetInformationProcess(IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
IN PVOID ProcessInformation,
IN ULONG ProcessInformationLength)
{
PEPROCESS Process;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
ACCESS_MASK Access;
NTSTATUS Status;
HANDLE PortHandle = NULL;
HANDLE TokenHandle = NULL;
PROCESS_SESSION_INFORMATION SessionInfo = {0};
PVOID ExceptionPort;
PAGED_CODE();

/* Verify Information Class validity */
#if 0
Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
PsProcessInfoClass,
RTL_NUMBER_OF(PsProcessInfoClass),
ProcessInformation,
ProcessInformationLength,
PreviousMode);
if (!NT_SUCCESS(Status)) return Status;
#endif

/* Check what class this is */
Access = PROCESS_SET_INFORMATION;
if (ProcessInformationClass == ProcessSessionInformation)
{
/* Setting the Session ID needs a special mask */
Access |= PROCESS_SET_SESSIONID;
}
else if (ProcessInformationClass == ProcessExceptionPort)
{
/* Setting the exception port needs a special mask */
Access |= PROCESS_SUSPEND_RESUME;
}

/* Reference the process */
Status = ObReferenceObjectByHandle(ProcessHandle,
Access,
PsProcessType,
PreviousMode,
(PVOID*)&Process,
NULL);
if (!NT_SUCCESS(Status)) return Status;

/* Check what kind of information class this is */
switch (ProcessInformationClass)
{
/* Quotas and priorities: not implemented */
case ProcessQuotaLimits:
case ProcessBasePriority:
case ProcessRaisePriority:
Status = STATUS_NOT_IMPLEMENTED;
break;
...
}
...
}


Rho zut alors reatos n'implémente pas encore cette fonctionnalité, en attendant si un reverser kernel windows dans l'âme avec quelques connaissances en mémoire virtuelle sous windows veut bien nous éclairer avec ce syscall ( perso j'y connais rien à ces syscall windows ni comment les tracer ), je sais que neitsabes avez commencé avec quelques ProcessInformationClass mais pas celui la donc voila.

Bon sinon ce que je pense de cette fonction, elle réside surement tout simplement dans un système de swap à la con qui vire les pages physiques les moins utilisées sans touchés aux pages virtuelles juste au cas où on en ait encore besoin sinon Access violation dans ta face et après tout 2Go en espace user de mémoire virtuelle ya de quoi faire alors que généralement la ram ne dépasse pas souvent les 1Go et il y a pas mal d'autre chose dans la mémoire physique alors que la mémoire virtuelle est spécifique au processus.

Dans tout les cas c'est une fonction sympa, on pourrait faire un petit tools qui fassent ça sur tout les process et pas seulement firefox car je suis sur qu'il doit bien y avoir dans d'autre process des fuites de mémoire.

http://msdn.microsoft.com/en-us/library/ms682606.aspx

Have fun with this function !!!

Aucun commentaire: