C#/.NET 对象使用多少内存?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/426396/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How much memory does a C#/.NET object use?
提问by FerranB
I'm developing an application which currently have hundreds of objects created.
我正在开发一个当前创建了数百个对象的应用程序。
Is it possible to determine (or approximate) the memory allocated by an object (class instance)?
是否可以确定(或近似)对象(类实例)分配的内存?
采纳答案by Rauhotz
You could use a memory profiler like
您可以使用内存分析器,例如
.NET Memory Profiler (http://memprofiler.com/)
.NET 内存分析器 ( http://memprofiler.com/)
or
或者
CLR Profiler (free) (http://clrprofiler.codeplex.com/)
CLR Profiler(免费)(http://clrprofiler.codeplex.com/)
回答by George Stocker
The ANTS memory profilerwill tell you exactly how much is allocated for each object/method/etc.
该蚂蚁内存分析器会确切地告诉你多少分配给每个对象/方法/等。
回答by Charles Bretana
Each "class" requires enough memory to hold all of it's jit-compiled code for all it's members that have been called by the runtime, (although if you don;t call a method for quite some time, the CLR can release that memory and re-jit it again if you call it again... plus enough memory to hold all static variables declared in the class... but this memory is allocated only once per class, no matter how many instances of the class you create.
每个“类”都需要足够的内存来保存由运行时调用的所有成员的所有 jit 编译代码(尽管如果您在很长一段时间内不调用方法,CLR 可以释放该内存并如果再次调用它,则再次重新 jit ......加上足够的内存来保存类中声明的所有静态变量......但是这个内存只分配给每个类一次,无论你创建了多少个类的实例。
For each instance of the class that you create, (and has not been Garbage collected) you can approximate the memory footprint by adding up the memory usage by each instance-based declared variable... (field)
对于您创建的类的每个实例(并且尚未被垃圾收集),您可以通过将每个基于实例的声明变量的内存使用情况相加来估算内存占用...(字段)
reference variables (refs to other objects) take 4 or 8 bytes (32/64 bit OS ?) int16, Int32, Int64 take 2,4, or 8 bytes, respectively...
引用变量(对其他对象的引用)占用 4 或 8 个字节(32/64 位操作系统?)int16、Int32、Int64 分别占用 2,4 或 8 个字节...
string variable takes extra storage for some meta data elements, (plus the size of the address pointer)
字符串变量为一些元数据元素占用额外的存储空间,(加上地址指针的大小)
In addition, each reference variable in an object could also be considered to "indirectly" include the memory taken up on the heap by the object it points to, although you would probably want to count that memory as belonging to that object not the variable that references it...
此外,对象中的每个引用变量也可以被视为“间接”包括它指向的对象在堆上占用的内存,尽管您可能希望将该内存视为属于该对象而不是该对象的变量参考它...
etc. etc.
等等等等
回答by John Sheehan
Here's a related postwhere we discussed determining the size of reference types.
回答by Sean
To get a general sense for the memory allocation in your application, use the following sos command in WinDbg
要大致了解应用程序中的内存分配,请在 WinDbg 中使用以下 sos 命令
!dumpheap -stat
Note that !dumpheap only gives you the bytes of the object type itself, and doesn't include the bytes of any other object types that it might reference.
请注意, !dumpheap 只给你对象类型本身的字节,不包括它可能引用的任何其他对象类型的字节。
If you want to see the total held bytes (sum all the bytes of all objects referenced by your object) of a specific object type, use a memory profiler like dot Trace - http://www.jetbrains.com/profiler/
如果您想查看特定对象类型的总持有字节数(对象引用的所有对象的所有字节数之和),请使用内存分析器,如 dot Trace - http://www.jetbrains.com/profiler/
回答by varun
A coarse way could be this in-case you wanna know whats happening with a particular object
一种粗略的方法可能是这样,以防您想知道特定对象发生了什么
// 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);
process wide stuff could be obtained perhaps like this
可能像这样获得过程广泛的东西
long Process_MemoryStart = 0;
Process MyProcess = System.Diagnostics.Process.GetCurrentProcess();
Process_MemoryStart = MyProcess.PrivateMemorySize64;
hope this helps ;)
希望这可以帮助 ;)
回答by Dave Black
You can also use WinDbg and either SOS or SOSEX (like SOS with with a lot more commands and some existing ones improved) WinDbg extensions. The command you would use to analyze an object at a particular memory address is !objsize
您还可以使用 WinDbg 和 SOS 或 SOSEX(如 SOS 具有更多命令和一些改进的现有命令)WinDbg 扩展。用于分析特定内存地址处的对象的命令是 !objsize
One VERY important item to remember is that !objsize only gives you the size of the class itself and DOES NOT necessarily include the size of the aggregate objects contained inside the class - I have no idea why it doesn't do this as it is quite frustrating and misleading at times.
要记住的一个非常重要的项目是 !objsize 只给你类本身的大小,并不一定包括类中包含的聚合对象的大小 - 我不知道为什么它不这样做,因为它很有时令人沮丧和误导。
I've created 2 Feature Suggestions on the Connect website that ask for this ability to be included in VisualStudio. Please vote for the items of you would like to see them added as well!
我在 Connect 网站上创建了 2 个功能建议,要求将此功能包含在 VisualStudio 中。请为您希望看到它们添加的项目投票!
EDIT:I'm adding the following to clarify some info from the answer provided by Charles Bretana:
编辑:我添加以下内容以澄清 Charles Bretana 提供的答案中的一些信息:
- the OP asked about the size of an 'object' not a 'class'. An object is an instance of a class. Maybe this is what you meant?
- The memory allocated for an object does not include the JITted code. The JIT code lives in its own 'JIT Code Heap'.
- The JIT only compiles code on a method by method basis - not at a class level. So if a method never gets called for a class, it is never JIT compiled and thus never has memory allocated for it on the JIT Code Heap.
- OP 询问“对象”而不是“类”的大小。对象是类的实例。也许这就是你的意思?
- 为对象分配的内存不包括 JIT 代码。JIT 代码存在于它自己的“JIT 代码堆”中。
- JIT 只在一个方法的基础上编译代码 - 而不是在类级别。因此,如果一个方法永远不会被类调用,它永远不会被 JIT 编译,因此永远不会在 JIT 代码堆上为它分配内存。
As an aside, there are about 8 different heaps that the CLR uses:
顺便说一句,CLR 使用了大约 8 个不同的堆:
- Loader Heap: contains CLR structures and the type system
- High Frequency Heap: statics, MethodTables, FieldDescs, interface map
- Low Frequency Heap: EEClass, ClassLoader and lookup tables
- Stub Heap: stubs for CAS, COM wrappers, P/Invoke
- Large Object Heap: memory allocations that require more than 85k bytes
- GC Heap: user allocated heap memory private to the app
- JIT Code Heap: memory allocated by mscoreee (Execution Engine) and the JIT compiler for managed code
- Process/Base Heap: interop/unmanaged allocations, native memory, etc
- 加载器堆:包含 CLR 结构和类型系统
- 高频堆:statics、MethodTables、FieldDescs、接口图
- 低频堆:EEClass、ClassLoader 和查找表
- 存根堆:用于 CAS、COM 包装器、P/Invoke 的存根
- 大对象堆:需要超过 85k 字节的内存分配
- GC Heap:用户分配给应用程序私有的堆内存
- JIT 代码堆:由 mscoreee(执行引擎)和 JIT 编译器为托管代码分配的内存
- 进程/基堆:互操作/非托管分配、本机内存等
HTH
HTH
回答by serhio
If you can - Serialize it!
如果可以的话 - 序列化它!
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
回答by satnhak
There is the academic question of What is the size of an object at runtime?And that is interesting, but it can only be properly answered by a profiler that is attached to the running process. I spent quite a while looking at this recently and determined that there is no generic method that is accurate and fast enough that you would ever want to use it in a production system. Simple cases like arrays of numerical types have easy answers, but beyond this the best answer would be Don't bother trying to work it out. Why do you want to know this? Is there other information available that could serve the same purpose?
有一个学术问题是运行时对象的大小是多少?这很有趣,但它只能由附加到正在运行的进程的分析器正确回答。我最近花了很长时间研究这个问题,并确定没有任何通用方法可以准确和快速地让您想在生产系统中使用它。像数值类型数组这样的简单情况有简单的答案,但除此之外,最好的答案是不要费心去解决它。你为什么想知道这个?是否有其他可用的信息可以用于相同的目的?
In my case I ended up wanting to answer this question because I had various data that were useful, but could be discarded to free up RAM for more critical services. The poster boys here are an Undo Stackand a Cache.
就我而言,我最终想要回答这个问题,因为我有各种有用的数据,但可以丢弃这些数据以释放 RAM 用于更关键的服务。这里的海报男孩是Undo Stack和Cache。
Eventually I concluded that the right way to manage the size of the undo stack and the cache was to query for the amount of available memory (it's a 64-bit process so it is safe to assume it is all available) and then allow more items to be added if there is a sufficiently large buffer of RAM and require items to be removed if RAM is running low.
最终我得出结论,管理撤消堆栈和缓存大小的正确方法是查询可用内存量(它是一个 64 位进程,因此可以安全地假设它全部可用)然后允许更多项目如果有足够大的 RAM 缓冲区并需要在 RAM 不足时删除项目,则添加。