J'ai un problème très étrange : dans notre application REST, nous avons introduit une option permettant de télécharger un WebPackage. Étant donné que ces paquets peuvent être assez volumineux une fois déballés, nous voulions nous assurer que la vérification de la mémoire par MemoryFailPoint se passe bien.
Sur mon IIS 7.5 local, cela fonctionne parfaitement, même jusqu'à une valeur maximale prévue de 2 Go. Sur notre serveur virtuel Windows Server 2008R2 x64 avec IIS 7.5, cela échoue inconditionnellement - même si l'on essaie seulement 1MB.
Le serveur virtuel est hébergé sur VMWare ESXi 4.1.0, 348481.
Voici l'exemple de code qui échoue sur la machine virtuelle :
using (MemoryFailPoint failPoint = new MemoryFailPoint(1))
{
... // deliberately excluded webpackage code
}
Et l'exception (en XML) :
<InsufficientMemoryException>
<Message>Insufficient memory to meet the expected demands of an operation, and this system is likely to never satisfy this request. If this is a 32 bit system, consider booting in 3 GB mode.</Message>
<StackTrace>
<Line>at System.Runtime.MemoryFailPoint..ctor(Int32 sizeInMegabytes)</Line>
<Line>at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)</Line>
<Line>at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)</Line>
<Line>at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)</Line>
<Line>at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)</Line>
<Line>at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</Line>
</StackTrace>
<UserDefinedInformation>
<failpointSizeInMegaBytes>1.00</failpointSizeInMegaBytes>
<gcTotalMemoryBeforeInMegaBytes>153.34</gcTotalMemoryBeforeInMegaBytes>
</UserDefinedInformation>
</InsufficientMemoryException>
Et une exception similaire sur ma machine - notez que j'ai eu besoin d'attribuer 64GB AVANT Je pourrais déclencher l'exception :
<InsufficientMemoryException>
<Message>Insufficient available memory to meet the expected demands of an operation at this time. Please try again later.</Message>
<StackTrace>
<Line>at System.Runtime.MemoryFailPoint..ctor(Int32 sizeInMegabytes)</Line>
<Line>at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)</Line>
<Line>at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)</Line>
<Line>at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)</Line>
<Line>at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)</Line>
<Line>at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</Line>
</StackTrace>
<UserDefinedInformation>
<failpointSizeInMegaBytes>65536.00</failpointSizeInMegaBytes>
<gcTotalMemoryBeforeInMegaBytes>150.63</gcTotalMemoryBeforeInMegaBytes>
</UserDefinedInformation>
</InsufficientMemoryException>
Cela me rend fou pour de vrai mais hé, prenez note des deux exceptions (très) différentes :
Serveur : Mémoire insuffisante pour répondre aux demandes attendues d'une opération, et ce système risque de ne jamais satisfaire cette demande. S'il s'agit d'un système 32 bits, envisagez de démarrer en mode 3 Go.
Utilisation de dotPeek de Jetbrains et de ce site web, http://reflector.webtropy.com/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/System/Runtime/MemoryFailPoint@cs/1305376/MemoryFailPoint@cs nous pouvons voir ce qui pourrait être le problème (bien que je ne sache toujours pas ce qu'il en est) :
// Check to see that we both have enough memory on the system
// and that we have enough room within the user section of the
// process's address space. Also, we need to use the GC segment
// size, not the amount of memory the user wants to allocate.
// Consider correcting this to reflect free memory within the GC
// heap, and to check both the normal & large object heaps.
ulong num1 = (ulong) sizeInMegabytes << 20;
this._reservedMemory = num1;
ulong size = (ulong)(Math.Ceiling((double)num1 / (double)MemoryFailPoint.GCSegmentSize) * (double)MemoryFailPoint.GCSegmentSize);
if (size >= MemoryFailPoint.TopOfMemory)
throw new InsufficientMemoryException(Environment.GetResourceString("InsufficientMemory_MemFailPoint_TooBig"));
Local : Mémoire disponible insuffisante pour répondre aux demandes attendues d'une opération à ce moment-là. Veuillez réessayer plus tard.
EDIT
Hans et moi avons discuté de la taille de la VM, mais comme j'en suis arrivé à la conclusion qu'elle est plus ou moins égale sur le serveur de développement et sur ma machine, je vais exclure cette partie pour le moment. Tous les conseils, suggestions, etc. sont les bienvenus.
Informations sur le processus
Process Name: w3wp
PID: 5716
User Name: NT AUTHORITY\NETWORK SERVICE
Working Set: 376.456 K
Peak Working Set: 432.400 K
Private Working Set: 320.684 K
Commit Size: 538.552 K
Handles: 919
Threads: 39
Système d'exploitation (WMI)
BootDevice: \Device\HarddiskVolume1
BuildNumber: 7601
BuildType: Multiprocessor Free
Caption: Microsoft Windows Server 2008 R2 Standard
CodeSet: 1252
CountryCode: 45
CreationClassName: Win32_OperatingSystem
CSCreationClassName: Win32_ComputerSystem
CSDVersion: Service Pack 1
CSName: SOME_NAME [MODIFIED]
CurrentTimeZone: 120
DataExecutionPrevention_32BitApplications: True
DataExecutionPrevention_Available: True
DataExecutionPrevention_Drivers: True
DataExecutionPrevention_SupportPolicy: 3
Debug: False
Description: Development Server
Distributed: False
EncryptionLevel: 256
ForegroundApplicationBoost: 2
FreePhysicalMemory: 5.366.516 K
FreeSpaceInPagingFiles: 8.368.456 K
FreeVirtualMemory: 12.985.412 K
InstallDate: 17-01-2011 15:01:55
LargeSystemCache: null
LastBootUpTime: 11-09-2012 14:44:33
LocalDateTime: 03-10-2012 14:13:47
Locale: 0406
Manufacturer: Microsoft Corporation
MaxNumberOfProcesses: 4294967295
MaxProcessMemorySize: 8.589.934.464 K
MUILanguages: System.Object[]
Name: Microsoft Windows Server 2008 R2 Standard |C:\Windows|\Device\Harddisk0\Partition2
NumberOfLicensedUsers: null
NumberOfProcesses: 70
NumberOfUsers: 7
OperatingSystemSKU: 7
Organization:
OSArchitecture: 64-bit
OSLanguage: 1033
OSProductSuite: 272
OSType: 18
OtherTypeDescription: null
PAEEnabled: null
PlusProductID: null
PlusVersionNumber: null
Primary: True
ProductType: 3
RegisteredUser: Windows User
SerialNumber: 11111-111-1111111-11111 [MODIFIED]
ServicePackMajorVersion: 1
ServicePackMinorVersion: 0
SizeStoredInPagingFiles: 8.388.152 K
Status: OK
SuiteMask: 272
SystemDevice: \Device\HarddiskVolume2
SystemDirectory: C:\Windows\system32
SystemDrive: C:
TotalSwapSpaceSize: null
TotalVirtualMemorySize: 16.774.452 K
TotalVisibleMemorySize: 8.388.152 K
Version: 6.1.7601
WindowsDirectory: C:\Windows
Capture d'écran de VMMap à partir du serveur de développement
Comme je suis curieux de connaître la taille virtuelle, je télécharge VMMap de Sysinternals : http://technet.microsoft.com/en-us/sysinternals/dd535533
Capture d'écran VMMap de ma machine locale (où MemoryFailPoint fonctionne comme prévu)
Je ne comprends toujours pas pourquoi le MemoryFailPoint échoue - et il est important (surtout quand on parle de Windows Azure ou d'autres fournisseurs de nuages) de s'assurer qu'il y a suffisamment de mémoire pour l'opération. Pour prendre un exemple, une instance ExtraSmall échouera (même avec son architecture x64) quelque part dans le processus en raison des ressources très limitées - cela pourrait être évité par le MemoryFailPoint, garantissant ainsi un état valide des données.
Toute aide est la bienvenue.