C#/ .NET对象使用多less内存?
我正在开发一个当前有数百个对象创build的应用程序。
是否有可能确定(或近似)由对象(类实例)分配的内存?
你可以使用像内存分析器
.NET内存分析器( http://memprofiler.com/ )
要么
CLR Profiler(免费)( http://clrprofiler.codeplex.com/ )
一个粗略的方法可能是这种情况下,你想知道什么事情发生在一个特定的对象
// Measure starting point memory use GC_MemoryStart = System.GC.GetTotalMemory(true); // Allocate a new byte array of 20000 elements (about 20000 bytes) MyByteArray = new byte[20000]; // Obtain measurements after creating the new byte[] GC_MemoryEnd = System.GC.GetTotalMemory(true); // Ensure that the Array stays in memory and doesn't get optimized away GC.KeepAlive(MyByteArray);
过程广泛的东西可能是这样得到的
long Process_MemoryStart = 0; Process MyProcess = System.Diagnostics.Process.GetCurrentProcess(); Process_MemoryStart = MyProcess.PrivateMemorySize64;
希望这可以帮助 ;)
ant内存分析器会告诉你到底有多less分配给每个对象/方法/等。
这里有一个相关的post ,我们讨论了确定引用types的大小。
你也可以使用WinDbg和SOS或者SOSEX(像SOS一样有更多的命令和一些现有的改进)WinDbg扩展。 您将用于分析特定内存地址处的对象的命令是!objsize
一个非常重要的事情要记住的是!!objsize只给你这个类的大小本身,并不一定包含在类中包含的聚合对象的大小 – 我不知道为什么它不这样做,因为它是相当有时令人沮丧和误导。
我在Connect网站上创build了两个functionbuild议,要求将这个function包含在VisualStudio中。 请投票选出你想要看到的项目!
编辑:我添加以下来澄清查尔斯Bretana提供的答案中的一些信息:
- OP询问了“对象”而不是“类”的大小。 一个对象是一个类的一个实例。 也许这就是你的意思?
- 分配给对象的内存不包含JITted代码。 JIT代码位于自己的“JIT代码堆”中。
- JIT只是按方法编译代码,而不是在课堂上。 所以如果一个方法永远不会被调用一个类,它永远不会被JIT编译,因此从来没有在JIT代码堆上为它分配内存。
顺便说一下,CLR使用了大约8种不同的堆:
- Loader Heap:包含CLR结构和types系统
- 高频堆:静态,方法表,FieldDescs,接口映射
- 低频堆:EEClass,ClassLoader和查找表
- 存根堆:存根CAS,COM包装,P / Invoke
- 大对象堆:需要超过85k字节的内存分配
- GC堆:用户分配给应用程序专用的堆内存
- JIT代码堆:由mscoreee(执行引擎)分配的内存和托pipe代码的JIT编译器
- 进程/基本堆:互操作/非托pipe分配,本地内存等
HTH
要获得应用程序中内存分配的一般意义,请在WinDbg中使用以下sos命令
!dumpheap -stat
请注意,!dumpheap只给出对象types本身的字节,并不包含它可能引用的任何其他对象types的字节。
如果要查看特定对象types的总保留字节数(将您的对象引用的所有对象的所有字节总和),请使用像Trace Trace这样的内存分析器 – http://www.jetbrains.com/profiler/
每个“类”都需要足够的内存来存放运行时调用的所有成员的所有jit编译代码(尽pipe如果不调用一段时间的方法,CLR可以释放内存,如果再次调用它,再重新debugging一次…加上足够的内存来容纳在类中声明的所有静态variables…但是这个内存只能在每个类中分配一次,无论您创build的类有多less个实例。
对于您创build的类的每个实例(并没有收集垃圾),您可以通过将每个基于实例的声明variables的内存使用量相加来近似内存占用量(字段)
引用variables(引用其他对象)需要4或8字节(32/64位OS?)int16,Int32,Int64分别采取2,4或8字节…
stringvariables需要额外的存储一些元数据元素,(加上地址指针的大小)
另外,对象中的每个引用variables也可以被认为是“间接”包含它指向的对象在堆上占用的内存,尽pipe您可能想要将该内存计算为属于该对象的variables引用它…
等等
如果可以的话 – 序列化它!
Dim myObjectSize As Long Dim ms As New IO.MemoryStream Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter() bf.Serialize(ms, myObject) myObjectSize = ms.Position
在运行时有什么大小的学术问题? 这很有趣,但只能通过与正在运行的进程相关的分析器来正确回答。 我最近花了一段时间看这个,确定没有一个通用的方法是准确和快速的,以至于你想在生产系统中使用它。 像数组types的简单情况下有简单的答案,但除此之外,最好的答案是不要试图解决它。 你为什么想知道这个? 是否还有其他可用于相同目的的信息?
在我的情况下,我最终想要回答这个问题,因为我有各种有用的数据,但可以丢弃,以释放RAM的更关键的服务。 这里的海报男孩是一个撤消堆栈和一个caching 。
最后我得出结论:pipe理撤销堆栈和caching大小的正确方法是查询可用内存量(这是一个64位进程,因此可以安全地假设它是全部可用的),然后允许更多的项目如果有足够大的RAM缓冲区,并且要求在RAM运行低时需要删除项目,则需要添加。