创建和编写XML文件会引发异常 - >系统内存不足异常?

时间:2013-10-22 15:17:50

标签: c# .net xna garbage-collection


我已经开发了一段时间在XNA中称为“体素”的小游戏。一个.NET C#像Minecraft游戏。 我使用一个简单的概念来保​​存和读取我的游戏中的数据来构建世界地图。一切都存储在xml文件中。

现在我正在尝试加载更大的地图,并且在生成地图时会出现“paf”异常:

  

[系统内存不足]

我不明白为什么,因为异常被提出后我的 文件不是很重,大约<​​strong> 70 mb 。 在生成高达70 mb的 XML文件

期间看到异常提升是否正常?

使用的开发环境

  • Microsoft Windows 7(x64)位
  • Visual Studio 2012专业人员更新3
  • 8192 Ram
  • Intel i5 CPU 2.5 Ghz(4 cpus)

我确实使用CLR分析器进行测试,以检查垃圾收集器的工作原理:

enter image description here enter image description here

我初始化我的XmlWritter的代码:

    private XmlTextWriter myXmlTextWriter ;


    #region prepareNewWorldXmlFIle
    private void PreparedNewWorldXmlFile()
    {
        Stream fs = new FileStream(currentPath + "World\\world.xml", FileMode.Create);

        myXmlTextWriter = new XmlTextWriter(fs,Encoding.ASCII);
        myXmlTextWriter.Formatting = Formatting.Indented;
        myXmlTextWriter.WriteStartDocument(false);
        myXmlTextWriter.WriteComment("World Map ID:");
        //World and his attribute
        myXmlTextWriter.WriteStartElement("World");
        myXmlTextWriter.WriteStartElement("Matrix", null);
        myXmlTextWriter.WriteStartElement("Regions");
    }
    #endregion

我用来生成世界地图并编写xml文件的代码:

    //Octree calcul and generate map to xml file
    foreach (Region region in arcadia.world.Regions)
    {
        isAllCheckSameIdOctree = false;
        if (isFirstGenerationWorld)
        {
            //Regions and attributes
            myXmlTextWriter.WriteStartElement("Region");
            myXmlTextWriter.WriteAttributeString("id", indexRegion.ToString());
            myXmlTextWriter.WriteAttributeString("min", "x:" + region.PositionMin.X + ";y:" + region.PositionMin.Y + ";z:" + region.PositionMin.Z);
            myXmlTextWriter.WriteAttributeString("max", "x:" + region.PositionMax.X + ";y:" + region.PositionMax.Y + ";z:" + region.PositionMax.Z);
            myXmlTextWriter.WriteStartElement("Structures");
            myXmlTextWriter.WriteAttributeString("type", "cube");
        }
        indexRegion++;
        if (region.Matrice != null)
        {
            //If the node to generate contain minimum a height divisible by 2
            if (((region.PositionMax.Y - region.PositionMin.Y) / 2) > 2)
            {
                //generate and octree by 8
                GenerateNodes(region, region.PositionMin, 8);
            }
            else if (((region.PositionMax.Y - region.PositionMin.Y) / 2) <= 2)
            {
                //generate and octree by 4
                GenerateNodes(region, region.PositionMin, 4);
            }
            while (!isAllCheckSameIdOctree)
            {
                if (nodeToRegenerate != null && needRecurseBuild)
                {
                    //if the node is greater than 2
                    if (nodeToRegenerate.TotalHeight > 2)
                    {
                        nodeToRegenerate = GenerateNodes(nodeToRegenerate, region, nodeToRegenerate.Position, 8);
                        if (nodeToRegenerate == null)
                        {
                            isAllCheckSameIdOctree = true;
                        }

                    }
                    else if (nodeToRegenerate.TotalHeight <= 2)
                    {
                        nodeToRegenerate = GenerateNodes(nodeToRegenerate, region, nodeToRegenerate.Position, 4);
                        if (nodeToRegenerate == null)
                        {
                            isAllCheckSameIdOctree = true;
                        }
                    }
                }
                else
                {
                    isAllCheckSameIdOctree = true;
                }
            }
            if (isFirstGenerationWorld)
            {
                myXmlTextWriter.WriteEndElement();//Ferme le noeud Structures
                myXmlTextWriter.WriteEndElement();//Ferme le noeud Region
                myXmlTextWriter.Flush();
            }
        }
        else
        {
            if (isFirstGenerationWorld)
            {
                myXmlTextWriter.WriteEndElement();//Ferme le noeud Structures
                myXmlTextWriter.WriteEndElement();//Ferme le noeud Region
                myXmlTextWriter.Flush();
            }
        }
    }
    if (isFirstGenerationWorld)
    {
        myXmlTextWriter.WriteEndElement();//Ferme le noeud Regions
        myXmlTextWriter.WriteEndElement();//Ferme le noeud World
        myXmlTextWriter.Flush();
        myXmlTextWriter.Close();
    }

在我的generatedNode函数中捕获异常,请参阅下面的更多信息

enter image description here

我的generatedNode函数递归,其中异常触发“系统内存不足异常

#region ReGenerateWorld
    private Node GenerateNodes(Node nodeToRegenerate, Region region, Vector3 position, int countToCut)
    {
        //Relative dimension of the parent octree
        int widthParent = (int)nodeToRegenerate.TotalWidth / 2;
        int heightParent = (int)nodeToRegenerate.TotalHeight / 2;
        int lenghtParent = (int)nodeToRegenerate.TotalLenght / 2;

        //Relative dimension of the parent octree
        int widthNode = (widthParent) / (countToCut / (countToCut / 2));
        int heightNode = (heightParent) / (countToCut / (countToCut / 2));
        int lenghtNode = (lenghtParent) / (countToCut / (countToCut / 2));

        if (heightNode < 1)
        {
            heightNode = 1;
        }

        int refX = (int)position.X / 2;
        int refY = (int)position.Y / 2;
        int refZ = (int)position.Z / 2;
        int indexStartX = 0;
        int indexStartY = 0;
        int indexStartZ = 0;
        int nbrToCut = 0;
        if (heightParent >= 2)
        {
            nbrToCut = ((widthParent / (widthParent / 2))) * ((heightParent / (heightParent / 2))) * ((lenghtParent / (lenghtParent / 2)));
        }
        else
        {
            nbrToCut = 4;
            heightNode = 1;
        }
        //Calculate the number of cubic to cut

        //Génére les noeud racine
        int countVertical = 0;
        int calcPosX = 0;
        int calcPosY = 0;
        int calcPosZ = 0;
        int[][][] nodeMatriceWorld = null;
        bool firstTime;
        newNode = null;
        int idGroup = 0;
        bool isSameId = true;
        int idToCheck = 0;

        for (int index = 0; (index < nbrToCut) && (refY < 32); index++)
        {
            indexStartX = refX;
            indexStartY = refY;
            indexStartZ = refZ;

            try
            {
                nodeMatriceWorld = new int[widthNode][][];
                for (int i = 0; i < widthNode; i++)
                {
                    nodeMatriceWorld[i] = new int[lenghtNode][];
                    for (int j = 0; j < lenghtNode; j++)
                    {
                        nodeMatriceWorld[i][j] = new int[heightNode];
                    }
                }
            }
            catch (Exception ex)
            {
                // OUT OF MEMORY EXCEPTION HERE
                Console.Out.WriteLine(ex.Message);
            }
            firstTime = true;
            for (int epaisseur = 0; epaisseur < heightNode; epaisseur++, indexStartY++)
            {
                for (int ligne = 0; ligne < lenghtNode; ligne++, indexStartZ++)
                {
                    for (int collone = 0; collone < widthNode; collone++, indexStartX++)
                    {
                        if (firstTime)
                        {
                            calcPosX = indexStartX;
                            calcPosY = indexStartY;
                            calcPosZ = indexStartZ;

                            firstTime = false;
                        }
                        nodeMatriceWorld[collone][ligne][epaisseur] = matriceWorld[indexStartX][indexStartZ][indexStartY];
                    }

                    indexStartX = refX;
                }

                indexStartZ = refZ;
            }

            indexStartY = refY;
            idGroup = matriceWorld[calcPosX][calcPosZ][calcPosY];
            countVertical++;
            if (newNode != null)
            {
                newNode.Dispose();
            }

            newNode = new Node(nodeMatriceWorld, new Vector3(calcPosX, calcPosY, calcPosZ), idGroup, widthNode, heightNode, lenghtNode);
            region.Nodes[idGroup].Add(newNode);

            //Regions.Add(new Node(nodeMatriceWorld, new Vector3(calcPosX, calcPosY, calcPosZ), idGroup));
            refX += widthNode;

            if (countVertical >= 4)
            {
                refY = ((int)position.Y / 2) + heightNode;
                refX = ((int)position.X / 2);
                refZ = (int)position.Z / 2;
                countVertical = 0;
            }
            else if (countVertical == 2)
            {
                refZ = ((int)position.Z / 2) + lenghtNode;
                refX = ((int)position.X / 2);

            }
        }

        isSameId = true;
        nodeToRegenerate = null;
        needRecurseBuild = false;
        idToCheck = 0;
        // Check for each octree node if all are the same id
        foreach (List<Node> listNode in region.Nodes)
        {
            foreach (Node node in listNode.Where(m => m.isGroupSameId == false))
            {

                isSameId = true;
                idToCheck = node.matriceNode[0][0][0];
                node.isGroupSameId = true;//Le met a true au depart
                for (int epaisseur = 0; epaisseur < node.TotalHeight / 2 && isSameId; epaisseur++)
                {
                    for (int ligne = 0; ligne < node.TotalLenght / 2 && isSameId; ligne++)
                    {
                        for (int collone = 0; collone < node.TotalWidth / 2 && isSameId; collone++)
                        {
                            if (node.matriceNode[collone][ligne][epaisseur] != idToCheck)
                            {
                                isSameId = false;//si au moin un cube est différent on le marque
                                node.isGroupSameId = false;
                                //node.ItemGroup = node.matriceNode[collone, epaisseur, ligne];
                                nodeToRegenerate = node;
                                needRecurseBuild = true;
                                break;
                            }

                        }
                    }

                }

                if (!isSameId)
                {

                    break;
                }
                else
                {
                    if (idToCheck != 0)
                    {
                        isSameId = true;
                        node.isGroupSameId = true;
                        node.ItemGroup = idToCheck;
                        node.matriceNode = null;
                        node.Cube = new Primitives3D.Cube(node.ItemGroup, node.Position, new Vector3(0, 0, 0), node.TotalWidth, node.TotalHeight, node.TotalLenght);
                        //Initialise le cube qui représente le noeud
                        node.Cube.BuildCubeStart();
                        if (isFirstGenerationWorld)
                        {
                            myXmlTextWriter.WriteStartElement("Cube");
                            //Structures et ses attributs
                            myXmlTextWriter.WriteAttributeString("id", node.ItemGroup.ToString());
                            myXmlTextWriter.WriteAttributeString("min", "x:" + node.Cube.BoundingBox.Min.X + ";y:" + node.Cube.BoundingBox.Min.Y + ";z:" + node.Cube.BoundingBox.Min.Z);
                            myXmlTextWriter.WriteAttributeString("max", "x:" + node.Cube.BoundingBox.Max.X + ";y:" + node.Cube.BoundingBox.Max.Y + ";z:" + node.Cube.BoundingBox.Max.Z);

                            myXmlTextWriter.WriteEndElement();//Ferme le noeud xml cube
                            myXmlTextWriter.Flush();

                        }
                        //Ajoute l'id du noeud aux groupe d'id de la region s'il n'y était pas auparavant
                        if (!region.IdFound.Contains(node.ItemGroup) && node.ItemGroup != 0)
                        {
                            region.IdFound.Add(node.ItemGroup);
                        }
                    }
                    // If the node group is equal to an empty group id -> 0 it removes entire                        else
                    {
                        nodeToDelete = node;
                    }
                }
            }
            if (!isSameId)
            {

                break;
            }
            //Console.Out.WriteLine("Nodes cout generated : " + Nodes.Count.ToString());

        }
        // If a node does not contain all the same id -> go remove it
        if (!isSameId)
        {
            region.Nodes[nodeToRegenerate.ItemGroup].Remove(nodeToRegenerate);

        }
        if (nodeToDelete != null)
        {
            region.Nodes[nodeToDelete.ItemGroup].Remove(nodeToDelete);
        }
        nodeToDelete = null;
        //Dispose the resources
        newNode.Dispose();
        nodeMatriceWorld = null;


        return nodeToRegenerate;
    }
    #endregion

例外:

enter image description here

6 个答案:

答案 0 :(得分:1)

据我所知,问题不在于XML,而在于锯齿状数组 int [] [] [] nodeMatriceWorld 。它的大小太大,或者你创建这个数组的次数太多了。这是你的代码:

try
{
    nodeMatriceWorld = new int[widthNode][][];
    for (int i = 0; i < widthNode; i++)
    {
        nodeMatriceWorld[i] = new int[lenghtNode][];
        for (int j = 0; j < lenghtNode; j++)
        {
            nodeMatriceWorld[i][j] = new int[heightNode];
        }
    }
}
catch (Exception ex)
{
    // OUT OF MEMORY EXCEPTION HERE
    Console.Out.WriteLine(ex.Message);
}

检查widthNode,lenghtNode和heightNode。对于nodeMatriceWorld,您至少需要sizeof(int)* widthNode * lenghtNode * heightNode字节的内存。

答案 1 :(得分:0)

加载代码中的widthNode,lengthNode和heightNode有多大?如果有一些不合理的值到达那里,你最终可能会分配一个巨大的int数组 - 并且在大对象堆上分配足够大的对象,这对于管理起来要困难得多 - 对于一个,它不会被压缩。所以你有一个3 GB的进程,它只使用70 MB的内存。

重复加载(和释放)时是否发生异常,或者如果每个应用程序运行只加载一个节点,是否也会发生异常? CLR分析器中的地址视图对象有助于查看实际内存排列 - 如果堆碎片是您的问题,您将很容易看到可用空间间隙。

最后但并非最不重要的是,OutOfMemoryException可能由于某种原因完全错误 - 通常的罪魁祸首往往是在数组构造函数中获取错误的值(new int [int.MaxValue]将失败,因为例子)。

答案 2 :(得分:0)

当堆栈内存不足时,使用递归方法可能会导致内存不足。基本上,你的递归要么是无限的,要么接近它足以耗尽为堆栈保留的内存。

答案 3 :(得分:0)

我最近在通过XSLT处理XML时出现了类似的错误。我的文件只有5MB。我将我的XSLT处理改为.net类(使用MS转换工具进行转换)并解决了问题。显然是XSLT处理器的一些错误。

您可能遇到类似的问题,并且正如其他用户所建议的那样尝试使用不同的XML文档处理器,因为您使用的可能存在错误或限制。

答案 4 :(得分:0)

首先, 请确保在使用后关闭FileStream。 例子) - 这是最好的做法之一。

private void PreparedNewWorldXmlFile()
{
    using(Stream fs = new FileStream(currentPath + "World\\world.xml", FileMode.Create))
    {
        myXmlTextWriter = new XmlTextWriter(fs,Encoding.ASCII);
        myXmlTextWriter.Formatting = Formatting.Indented;
        myXmlTextWriter.WriteStartDocument(false);
        myXmlTextWriter.WriteComment("World Map ID:");
        //World and his attribute
        myXmlTextWriter.WriteStartElement("World");
        myXmlTextWriter.WriteStartElement("Matrix", null);
        myXmlTextWriter.WriteStartElement("Regions");
    }
}

我认为您应该在您的区域类实例中释放所有节点对象。 因为GC不会收集您的区域类实例,但是您将其设置为null。

答案 5 :(得分:0)

看来你试图用三维数组来表示地图, 使用heightmap,但您只需要2个维度。

例如: 数组:int map [x] [y]; 其中map [x] [y]的值是z。

这样你需要更少的内存来解决你的问题