实例类构造函数被调用时的内存分配 [英] memory allocation when instance class constructor is called

查看:126
本文介绍了实例类构造函数被调用时的内存分配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说明实例类的构造函数被调用时的整个过程
堆栈和堆中发生了什么变化

Explain the whole process when a constructor of an instance class is called
what changes take place in stack and heap

推荐答案

您具体提到了构造函数,就像它是某些特殊情况一样,不是.说到内存分配,您的代码是在构造函数中还是在方法中都没有区别.

让我们来看看内存分配是如何工作的.
You mention the constructor specifically, like it is some special case, it is not. When it comes to memory allocation there is no difference whether your code is in a constructor or method.

Lets go though how the memory allocation works, kinda.
public class AClass
{
    private int _myField;

    public AClass()
    {
        int i = 0; // 1
        _myFields = 0; // 2

        AClass aClass = new AClass(); // 3
        // Note StackOverflowException here, this is just to show there is no 
        // difference between memory allocation in a constracutor and a method.
    }

    public static AClass Create()
    {
        int i = 0; // 4

        AClass aClass = new AClass(); // 5

        aClass._myField = 0; // 6

        return aClass;
    }
}



1-存储在堆栈中
2-存储在堆中
3-引用存储在堆栈上,而对象存储在堆上.
4-存储在堆栈中
5-引用存储在堆栈上,而对象存储在堆上.
6-存储在堆中

正如我所说的那样,这有点儿起作用,我说这是因为您不能100%确定存储位置.
Microsoft的C#实现将所有短期值存储在堆栈或寄存器中,并将长期值存储在堆中.那些编译器是短命的那些被认为是长命的.

需要注意的重要一件事.许多书籍和其他资料来源说,值类型总是存储在堆栈中,这是并非正确的.值类型只有短暂存在时才会存储在堆栈中.

如果您正在使用其他一些诸如Mono之类的C#实现,则上述所有内容都是无效的. Mono可能会做完全相同的事情,但很可能不会.就我所知,Mono将所有内存存储在堆中.



1 - is stored on the stack
2 - is stored in the heap
3 - the reference is stored on the stack and the object is stored on the heap.
4 - is stored on the stack
5 - the reference is stored on the stack, and the object is stored on the heap.
6 - is stored in the heap

As I said this is how it kinda works, and I say kinda because you can''t be 100% sure of the storage location.
Microsofts implementation of C# stores all short-lived values on the stack or registers and long-lived values on the heap. Those that the compiler is short-lived is assumed to be long-lived.

One important thing to note. Many books and other sources say value types are always stored on the Stack, this is not true. Value types are only stored on the Stack when they are short-lived.

If you''re using some other C# implementation like Mono all that is stated above is null and void. Mono might do the exact same thing, it most likely does not. For all I know Mono stores all memory in the Heap.


表达式实例类的构造函数"非常不准确.在调用构造函数之前,没有实例.存在某个类的变量,但它尚未引用任何实例.该实例由构造函数创建并分配给变量.从那一刻起,它开始引用一些类实例.在构造函数调用之前,变量可以为null或引用其他实例.该实例与您调用的构造函数无关.它甚至可以是不同的类型-变量的编译时类型不必与实例的(运行时)类型相同-这是一个基本的OOP方面,它允许 late绑定多态.

而且,不需要类类型的变量.您可以不考虑返回值而调用构造函数.当只需要构造函数调用的副作用时,可以完成此操作.

您会看到,即使在堆积和堆放之前,也需要进行大量概念上的澄清.

现在,关于堆栈和堆,什么都没有发生,只针对类.

堆栈的压入和弹出方法与任何方法调用相同,没有区别.同样,在调用之前,构造函数主体执行期间和调用之后还有时间.通常,调用之前和之后的堆栈看起来是相同的,如果返回的实例和out/ref参数的值在堆栈中,则仅更改它们.在执行构造函数主体期间,通过构造函数代码的所有参数和堆栈(局部)变量所需的字节数,可使堆栈更深(指令指针减少).为每个参数分配的大小取决于in参数的参数大小,并且等于out/ref参数的System.IntPtr大小.在执行期间,每次构造函数代码直接或间接调用某个方法或属性时,都以相同的方式推送和弹出堆栈.

通过堆,分配了保存实例所需的内存,另外,堆的一部分由构造函数主体的执行分配,因为它可以创建其他对象的实例.

所有这些都专门与C#相关,但与整个.NET不相关.在C ++/CLI(显然是原始IL)中,即使引用的对象也不必在堆上分配.即使对于引用类型,C ++/CLI也可以支持值语义;它也可以完全像C#一样处理堆和CLR引用,也可以将它们自由地组合到模型中.

—SA
The expression "a constructor of an instance class" is very inaccurate. Before a constructor is called there is no instance. There is a variable of some class, but it does not refer to any instance yet. The instance is created by the constructor and assigned to a variable. Since that moment, it starts referencing some class instance. Before the constructor call, the variable can be null or reference some other instance. That instance had nothing to do with the constructor you call; it can be even of different type — compile-time type of the variable does not have to be the same as the (run-time) type of the instance — this is a fundamental OOP aspect which allows for late binding and polymorphism.

Moreover, the variable of the class type is not required to exist. You can call a constructor disregarding the return value. This can be done when only the side effect of constructor call is needed.

You see, so much of conceptual clarification is needed, even before getting to stack and heap.

Now, as to stack and heap, nothing specific to classes happens.

Stack is pushed and popped the same way as in the case of any method call, no difference. Again, there is time before call, during the execution of constructor body and after the call. As it usually happens, the stack before and after the call looks identical, only the values of the returned instance and out/ref parameters are changed if they were on stack. During the execution of constructor body, the stack is made deeper (instruction pointer decreases) by the number of bytes needed for all the parameters and stack (local) variables of the constructor code. The size allocated for each parameter depends on parameter size for in parameters and is equal to the size System.IntPtr for out/ref parameters. During the execution, the stack is pushed and popped the same way each time some method or property is called by the constructor code, directly or indirectly.

With the heap, the memory needed to hold the instance is allocated, plus some of the heap is allocated by the the execution of constructor body, as it can create instances of other objects.

All this is related specifically to C# but not to entire .NET. In C++/CLI (and apparently raw IL), even the referenced objects do not have to be allocated on heap. C++/CLI can support value semantics even for reference types; it also can work with heap and CLR references exactly as C# or freely combine these to models.

—SA


这篇关于实例类构造函数被调用时的内存分配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆