这段代码会导致托管堆损坏吗?
本文关键字:损坏 段代码 代码 | 更新日期: 2023-09-27 18:10:35
我试图调试在垃圾收集期间发生在应用程序中的崩溃,并查看代码,我发现两个相关的代码片段,如果不是问题的原因,至少对我来说是可疑的:
[StructLayout(LayoutKind.Sequential, Size = 96, CharSet = CharSet.Ansi, Pack=1)]
public class MilbusData
{
public System.Int64 TimeStamp;
public System.Int16 Lane;
public System.Int16 TerminalAddress;
public System.Int16 TerminalSubAddress;
public System.Int16 Direction;
public System.Int64 ErrorCounter;
public System.Int64 MessageCounter;
public System.Int16 RTErrorState;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public System.UInt16[] Data;
}
请注意,根据我的理解,结构体实际上至少有98字节的大小,但被声明为96字节长(代码编译)。
第二段可疑的代码与上面的结构体有关:MilbusData^ ret = nullptr;
if (m_Stream->Read(m_RawData, 0, sizeof(TMilbusData)) == sizeof(TMilbusData))
{
GCHandle pinnedRawData = GCHandle::Alloc(m_RawData, GCHandleType::Pinned);
ret = (MilbusData^)Marshal::PtrToStructure(pinnedRawData.AddrOfPinnedObject(),
MilbusData::typeid);
pinnedRawData.Free();
}
其中m_RawData是一个简单的无符号字节数组,TMilbusData是类似于上述结构体的c++(本机)代码,定义为
typedef struct
{
__int64 TimeStamp;
short Lane;
short TerminalAddress;
short TerminalSubAddress;
short Direction;
__int64 ErrorCounter;
__int64 MessageCounter;
short RTErrorState;
unsigned char Data[64];
} TMilbusData;
我不确定的是,在第二种情况下,从本机结构体到托管引用类型的转换是否安全(注意,MilbusData没有声明为值类型)。
正如我所说,我们正在经历的崩溃通常发生在垃圾收集期间,但有时极其难以重现。我在另一个问题中给出了更多关于崩溃本身的细节,但我想问的是:
- 以上代码安全吗?
- 如果不是,它是否可以成为托管堆损坏的原因,并因此解释我们正在经历的崩溃?
EDIT:我可能应该问一下,我在代码中发现的问题(如本机代码和托管代码之间的结构大小不匹配)是否绝对是肯定的可能是导致GC崩溃的原因。问这个问题的原因是:1)c#编译器不会抱怨错误的结构大小,2)这个问题很难重现。我现在很难让它在"旧"版本中崩溃(结构体的大小是错误的),我想避免跟随可能的死胡同,因为每次测试可能需要许多天。
,但编译器不应该看到96字节不足以存储结构体并将其视为错误?在任何情况下,可以单独解释垃圾收集时的崩溃吗?
您可能只想存储一定数量的数据,例如32位整数的前16位。
通过说结构的大小被限制为96字节,如果您试图在结构中放置超过96字节,您将尝试超出基于结构大小分配的内存。
这意味着你将1)在结构中只保留96个字节2)当你试图放置超过分配的内存时,会遇到内存管理问题
正如我已经说过的,你的代码没有任何问题,它会编译。在这种情况下,它是不正确的,并且结构没有正确声明,所以你应该要么不声明大小,要么声明正确的大小。
编辑:我可能应该问一下这是绝对肯定的我在代码中发现的问题(如不匹配的结构)(本机代码和托管代码之间的大小)可能是导致崩溃的原因GC。问这个问题的原因是i) c#编译器不会抱怨2)这个问题很难解决复制。我现在很难把它装进去"旧"版本(结构的大小是错误的)和我想要的避免走到可能的死胡同,因为每次测试都需要很多天. .
所有我可以向你保证的是结构大小在96字节不正确,我不能告诉你如果你有崩溃连接到垃圾收集器的问题,是连接到这个结构。如果这个结构是错的其他结构是错的吗?
我会固定大小,并确保数据是正确的类型,以匹配您将从设备接收到的数据。