J’utilise VSTS2008 + C # + .Net 3.5 pour exécuter cette application console sur x64 Server 2003 Enterprise avec une mémoire physique de 12 Go.
Voici mon code, et je trouve lors de l’exécution de l’instruction bformatter.Serialize (stream, table), qu’il existe une exception de mémoire insuffisante. J’ai surveillé l’utilisation de la mémoire via l’onglet Perormance du Gestionnaire des tâches et je constate que seule la mémoire physique 2G est utilisée lors de la levée d’une exception. Elle ne devrait donc pas manquer de mémoire. 🙁
Des idées ce qui ne va pas? Toute limitation de la sérialisation .Net?
static DataTable MakeParentTable() { // Create a new DataTable. System.Data.DataTable table = new DataTable("ParentTable"); // Declare variables for DataColumn and DataRow objects. DataColumn column; DataRow row; // Create new DataColumn, set DataType, // ColumnName and add to DataTable. column = new DataColumn(); column.DataType = System.Type.GetType("System.Int32"); column.ColumnName = "id"; column.ReadOnly = true; column.Unique = true; // Add the Column to the DataColumnCollection. table.Columns.Add(column); // Create second column. column = new DataColumn(); column.DataType = System.Type.GetType("System.Ssortingng"); column.ColumnName = "ParentItem"; column.AutoIncrement = false; column.Caption = "ParentItem"; column.ReadOnly = false; column.Unique = false; // Add the column to the table. table.Columns.Add(column); // Make the ID column the primary key column. DataColumn[] PrimaryKeyColumns = new DataColumn[1]; PrimaryKeyColumns[0] = table.Columns["id"]; table.PrimaryKey = PrimaryKeyColumns; // Create three new DataRow objects and add // them to the DataTable for (int i = 0; i <= 5000000; i++) { row = table.NewRow(); row["id"] = i; row["ParentItem"] = "ParentItem " + i; table.Rows.Add(row); } return table; } static void Main(string[] args) { DataTable table = MakeParentTable(); Stream stream = new MemoryStream(); BinaryFormatter bformatter = new BinaryFormatter(); bformatter.Serialize(stream, table); // out of memory exception here Console.WriteLine(table.Rows.Count); return; }
merci d’avance, George
Remarque: DataTable
utilise par défaut le format de sérialisation xml utilisé dans 1. *, ce qui est incroyablement inefficace. Une chose à essayer est de passer au nouveau format :
dt.RemotingFormat = System.Data.SerializationFormat.Binary;
Concernant le manque de mémoire / 2 Go; Les objects .NET individuels (tels que l’ byte[]
derrière un MemoryStream
) sont limités à 2 Go. Peut-être essayez-vous d’écrire sur un FileStream
?
(edit: nope: essayé ça, toujours des erreurs)
Je me demande également si vous pouvez obtenir de meilleurs résultats (dans ce cas) en utilisant table.WriteXml(stream)
, peut-être avec une compression telle que GZIP si l’espace est une prime.
Comme indiqué précédemment, il s’agit d’un problème fondamental lorsque l’on souhaite obtenir des blocs de mémoire contigus de la taille d’un gigaoctet.
Vous serez limité par (en difficulté croissante)
Vous pouvez constater que vous manquez d’espace avant la limite CLR de 2
car le tampon de sauvegarde dans le stream est développé de manière à être «doublé», ce qui entraîne rapidement l’allocation du tampon dans le segment d’objects volumineux. Ce tas n’est pas compacté de la même manière que les autres tas (1) et il en résulte que le processus de construction jusqu’à la taille maximale théorique du tampon sous 2
fragments du LOH afin que vous ne trouviez pas un bloc contigu suffisamment grand avant ça arrive.
Par conséquent, si vous approchez de la limite, une approche d’atténuation consiste à définir la capacité initiale du stream de sorte qu’il dispose d’un espace suffisant dès le départ via l’ un des constructeurs .
Étant donné que vous écrivez dans le stream de mémoire dans le cadre d’un processus de sérialisation, il serait logique d’utiliser réellement les stream comme prévu et d’utiliser uniquement les données requirejses.
Peut-être que si vous nous dites ce que vous sérialisez un object de cette taille, nous pourrons peut-être vous dire de meilleures façons de le faire.
1) Le système d’exploitation est x64, mais l’application est-elle x64 (ou anycpu)? Sinon, il est limité à 2 Go.
2) Est-ce que cela se produit «tôt» ou après que l’application ait fonctionné pendant un certain temps (c’est-à-dire n sérialisations plus tard)? Cela pourrait-il être le résultat d’une fragmentation de tas d’objects volumineux …?
Fait intéressant, il passe en fait à 3,7 Go avant de générer une erreur de mémoire ici (Windows 7 x64). Apparemment, il faudrait environ le double de ce montant pour terminer.
Étant donné que l’application utilise 1,65 Go après avoir créé la table, il semble probable qu’elle atteigne la limite d’ byte[]
(ou tout object isolé) de 2 Go dont parle Marc Gravell (1,65 Go + 2 Go ~ = 3,7 Go).
Sur la base de ce blog , je suppose que vous pouvez allouer votre mémoire à l’aide de WINAPI et écrire votre propre implémentation MemoryStream à l’aide de celle-ci. Autrement dit, si vous vouliez vraiment faire cela. Ou écrivez-en un en utilisant plus d’un tableau de cours 🙂