Question

Je suis actuellement en train de travailler sur un ray-traceur dans le langage C# dans un projet de loisirs.Je suis en train de réaliser un décent, la vitesse de rendu par la mise en œuvre de quelques "trucs" à partir d'une implémentation c++ et exécuté dans un endroit de mal.

Les objets dans les scènes qui le ray-traceur rend sont stockés dans un KdTree structure et les nœuds de l'arborescence sont, à leur tour, stockées dans un tableau.L'optimisation je vais avoir des problèmes avec, est tout en essayant d'intégrer autant de nœuds de l'arborescence que possible dans une ligne de cache.L'un des moyens de le faire, c'est pour les nœuds de contenir un pointeur vers la gauche nœud enfant seulement.Il est alors implicite que le droit de l'enfant suit directement après celui de gauche dans le tableau.

Les nœuds sont les structures et lors de la construction de l'arbre, ils sont réussi à mettre dans le tableau par une mémoire statique gestionnaire de classe.Quand je commence à parcourir l'arbre, au premier abord, semble très bien fonctionner.Puis, à un stade précoce dans le rendu (sur la même place à chaque fois), la gauche de l'enfant pointeur du nœud racine est soudainement pointer un pointeur null.Je suis venu à la conclusion que la poubelle collecter a déplacé les structs que le tableau se trouve sur le tas.

J'ai essayé plusieurs choses à la broche de la adresses dans la mémoire, mais aucun d'entre eux semble durer toute la vie de l'application que j'en ai besoin.Le "fixe" mot-clé ne semble pour aider lors des appels de méthode, et en déclarant "fixe" les tableaux peuvent être effectuées uniquement sur les types simples qui un nœud n'est pas.Est-il une bonne façon de le faire, ou suis-je trop loin sur la voie de trucs C# n'était pas destiné.

Btw, l'évolution du c++, alors que peut-être le meilleur choix pour un programme de haute performance, n'est pas une option.

Était-ce utile?

La solution

Tout d'abord, si vous êtes à l'aide de C# normalement, vous ne pouvez pas soudainement obtenir une référence nulle en raison de la collecte des déchets à transporter des choses, parce que le garbage collector également des mises à jour toutes les références, si vous n'avez pas besoin de s'inquiéter à ce sujet à déplacer les objets autour.

Vous pouvez épingler des choses en mémoire, mais cela peut causer plus de problèmes qu'elle n'en résout.Pour une chose, il empêche le garbage collector de compactage de la mémoire correctement, et peut influer sur les performances de cette façon.

Une chose que je voudrais dire à partir de votre post, c'est que en utilisant les structures ne peuvent pas aider à la performance que vous l'espérez.C# ne parvient pas à en ligne des appels de méthode impliquant les structures, même si ils ont corrigé cela dans leur dernier runtime beta, les structures fréquemment ne pas effectuer aussi bien que ça.

Personnellement, je dirais que C++ astuces comme ce n'est pas en général ont tendance à transporter de plus en C#.Vous pourriez avoir à apprendre à laisser aller un peu;il y a peut être d'autres plus subtiles façons d'améliorer le rendement ;)

Autres conseils

Qu'est-ce que votre mémoire statique gestionnaire en train de faire?Sauf qu'il est en train de faire quelque chose de dangereux (P/Invoke, le code unsafe), le comportement que vous voyez est un bug dans votre programme, et non pas en raison du comportement de la CLR.

Deuxièmement, qu'entendez-vous par 'pointeur', à l'égard des liens entre les structures?Avez-vous littéralement signifie un dangereux KdTree* pointeur?Ne pas le faire.Au lieu de cela, utiliser un index dans le tableau.Depuis j'attends que tous les nœuds d'un arbre unique sont stockées dans le même tableau, vous n'aurez pas besoin d'une référence distincte de la matrice.Un seul indice ne.

Enfin, si vraiment vous devez vraiment utiliser KdTree* pointeurs, alors votre mémoire statique gestionnaire doit allouer un gros bloc en utilisant par ex.Maréchal.AllocHGlobal ou d'une autre mémoire non managée source;il doit à la fois traiter ce bloc comme un KdTree array (c'est à direindex un KdTree* C-style) et il devrait suballocate nœuds à partir de ce tableau, en cognant un "libre" pointeur.

Si vous devez redimensionner le tableau, alors vous devez mettre à jour tous les pointeurs, bien sûr.

La leçon de base ici est que dangereux pointeurs et de la mémoire gérée faire pas mélanger à l'extérieur de "fixe" de blocs, qui ont bien sûr des frame de pile affinité (c'est à direlorsque la fonction est de retour, le épinglé comportement s'en va).Il existe un moyen de pin objets arbitraires, comme votre tableau, à l'aide GCHandle.Alloc(yourArray, GCHandleType.Épinglé), mais vous avez presque certainement ne voulez pas aller dans cette voie.

Vous obtiendrez plus raisonnable des réponses, si vous les décrire plus en détail ce que vous faites.

Si vous vraiment voulez pour ce faire, vous pouvez utiliser le GCHandle.Alloc méthode pour spécifier qu'un pointeur doit être épinglé sans être automatiquement libéré à la fin de la portée, comme le fixe déclaration.

Mais, comme d'autres personnes l'ont dit, la faire, c'est de mettre une pression indue sur le garbage collector.Qu'en est juste la création d'une structure qui tient sur une paire de nœuds et de la gestion d'un tableau de NodePairs plutôt qu'un tableau de nœuds?

Si vraiment vous ne voulez pas avoir la incontrôlé de l'accès à une partie de la mémoire, vous feriez probablement mieux de l'allocation de la mémoire directement à partir du segment non géré plutôt que de façon permanente l'épinglage d'une partie du tas managé (ce qui empêche le tas de être en mesure de bien compact lui-même).Une façon simple et rapide à faire, ce serait d'utiliser le Maréchal.AllocHGlobal méthode.

Est-il vraiment prohibitif pour stocker la paire de référence de tableau et index?

Qu'est-ce que votre mémoire statique gestionnaire en train de faire?Sauf qu'il est en train de faire quelque chose de dangereux (P/Invoke, le code unsafe), le comportement que vous voyez est un bug dans votre programme, et non pas en raison du comportement de la CLR.

J'étais en fait en parlant à propos dangereux pointeurs.Ce que je voulais, c'était quelque chose comme Marshal.AllocHGlobal, bien que , avec une durée de vie dépassant un seul appel de méthode.À la réflexion, il semble que l'utilisation d'un index est la solution que j'ai peut être été trop pris en imitant le code c++.

Une chose que je voudrais dire à partir de votre post, c'est que en utilisant les structures ne peuvent pas aider à la performance que vous l'espérez.C# ne parvient pas à en ligne des appels de méthode impliquant les structures, même si ils ont corrigé cela dans leur dernier moment de l'exécution de la bêta, les structures fréquemment ne pas effectuer aussi bien que ça.

J'ai regardé un peu et je vois qu'il a été corrigé dans la .NET 3.5SP1;Je suppose que c'est ce que vous faisiez référence à l'exécution de la bêta.En fait, je comprends maintenant que ce changement a représenté pour un doublement de ma vitesse de rendu.Maintenant, les structures sont agressivement en-alignés, de l'amélioration de leurs performances grandement sur les systèmes X86 (64 avait mieux struct performance à l'avance).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top