I've been developing for some time a small game called 'voxel' in XNA. A .NET C# like Minecraft game. I use a simple concept to save and read data from my games to build the world map. Everything is stored in an xml file.
Now I'm trying to load a larger map, and 'paf' an exception is raised during the generation of my map:
[System out of memory exception]
I do not understand why, because after the exception is raised my file is not very heavy, it's about 70 mb. Is it normal to see an exception raise during the generation of an XML file up to 70 mb?
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
//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();
}
#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
You can do either of the following to address the error: Replace the call to the StringBuilder. StringBuilder(Int32, Int32) constructor with a call any other StringBuilder constructor overload. The maximum capacity of your StringBuilder object will be set to its default value, which is Int32.
To avoid this exception while working with StringBuilder, we can call the constructor StringBuilder. StringBuilder(Int32, Int32) and can set the MaxCapacity property to a value that will be large enough to serve the accommodation required when we expand the corresponding StringBuilder object.
Out of memory (OOM) is an often undesired state of computer operation where no additional memory can be allocated for use by programs or the operating system.
As I understand, you problem is not with XML, but in jagged array int[][][] nodeMatriceWorld. Its size is too large or you're creating this array too many times. Here is your code:
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);
}
Check widthNode, lenghtNode and heightNode. For nodeMatriceWorld you need at least sizeof(int) * widthNode * lenghtNode * heightNode bytes of memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With