以下方法用于将本机数据传输到托管数据 结构。 AppendDataToChannel方法确实分配了创建的数组 更大的结构。
我现在看到的是这个方法的执行时间是50%垃圾 采集。由于时间对我来说非常关键,我必须摆脱它。
我的假设是该数组中的“ - > SetValue”导致了 被重写为“垃圾收集”的值。有快速的方法吗? 更新数组中的值而不会导致此类行为? (有数千次调用 - > gt; SetValue)
template <typename Tnative, typename Tmanaged>
ChannelGroupData ^ NativeToManaged(I_ChannelGroup &aChannelGroup, unsigned int index, unsigned int count)
{
std::map< std::string, std::vector<Tnative> > v;
aChannelGroup.GetData(v, index, count);
ChannelGroupData^ result = gcnew ChannelGroupData(v.size());
for (std::map< std::string, std::vector<Tnative> >::const_iterator cMIt = v.begin(); cMIt != v.end(); ++cMIt)
{
std::string channelObjectPath(cMIt->first);
I_Channel *aChannel = aChannelGroup.GetChannelByObjectPath(channelObjectPath);
if (aChannel != NULL)
{
unsigned int vSize (cMIt->second.size());
DataType aType = static_cast<DataType>(aChannel->GetDataType());
int iIndex (0);
const std::vector<Tnative> *pChannelDataV (&cMIt->second);
array<Tmanaged>^ vResult = gcnew array<Tmanaged>(pChannelDataV->size());
for (std::vector<Tnative>::const_iterator cDIt = pChannelDataV->begin(); cDIt != pChannelDataV->end(); ++cDIt, ++iIndex)
{
vResult->SetValue((Tmanaged)(gcnew Tnative(*cDIt)), iIndex);
}
result->AppendDataToChannel(gcnew System::String(channelObjectPath.c_str()), vResult,static_cast<int>( aType), iIndex);
delete aChannel;
}
}
return result;
}
答案 0 :(得分:1)
我的假设是该数组中的“ - &gt; SetValue”导致被覆盖的值被“垃圾收集”。
这里没有问题:你在新数组上调用SetValue
,因此每个元素都是默认值。如果Tmanaged
是引用类型,则默认值为null,并且无需收集任何内容。如果Tmanaged
是值类型,则根本不会收集垃圾。
副手,我看到你的代码存在两个问题:
for (std::vector<Tnative>::const_iterator cDIt ...)
{
vResult->SetValue((Tmanaged)(gcnew Tnative(*cDIt)), iIndex);
}
gcnew
上致电Tnative
。如果是原生的,new
会不合适?Tnative
个对象;它在你正在迭代的向量中。你为什么要建造另一个?那就是说,我认为你的代码没有问题;我认为GC运作正常。
让我们考虑GC的工作原理:它有大量的对象,它存储在三个桶中。新分配的对象进入“Gen0”桶,然后它们移动到“Gen1”和“Gen2”桶,因为它们在垃圾收集中存活。
当分配新对象时,它们被放置在Gen 0中。当Gen 0填满时,GC会执行Gen 0的集合。任何不再使用的对象都会被收集,任何仍在使用的对象移动到第1代。(当第1代填满时,过程就会发生。我忘记第2代收集的触发条件是什么。)
所以,在你的方法中,你要分配一堆新对象。 (gcnew ChannelGroupData(v.size())
,gcnew array<Tmanaged>(pChannelDataV->size())
,gcnew Tnative(*cDIt)
和gcnew System::String
。)根据您拥有的数据量,您可能完全有可能分配足够的新对象,即Gen 0填充,GC完成Gen 0集合。
我在MSDN上发现了a blog post,它谈到了GC代的大小。根据这一点,代数的大小可能会根据您使用的运行时间而有所不同,但Gen 0的64 MB是写入帖子时的典型值。
当您从磁盘读取数据时,Gen 0存储桶会填满,垃圾收集器将启动并执行Gen 0收集。 这是分配大量新内存时的正常行为。另外,如果您从磁盘读取的数据大于64 MB,那么所有对象都将存活到第1代,那就是' ll触发Gen 1系列!他们将在第二代中存活下来,你也可能最终获得Gen 2系列,而且这些系列比第0代和第一代更昂贵。
如果您真的不想在读取数据时发生GC,那么我会采取预分配策略:提前分配您需要的所有管理对象,让GC做了它的事情,因为你分配了所有新的内存,然后保持对象很长一段时间。从磁盘读取数据时,替换已分配的托管对象上的值,GC将没有任何理由可以运行。