Does new always allocate on the heap in C++ / C# / Java
My understanding has always been, regardless of C++ or C# or Java, that when we use the new
keyword to create an object it allocates memory on the heap. I thought that new
is only needed for reference types (classes), and that primitive types (int, bool, float, etc.) never use new
and always go on the stack (except when they're a member variable of a class that gets instantiated with new
). However, I have been reading information that makes me doubt this long standing assum开发者_运维问答ption, at least for Java and C#.
For example, I just noticed that in C# the new
operator can be used to initialize a value type, see here. Is this an exception to the rule, a helper feature of the language, and if so, what other exceptions would there be?
Can someone please clarify this?
I thought that new is only needed for reference types (classes), and that primitive types (int, bool, float, etc.) never use new
In C++, you can allocate primitive types on the heap if you want to:
int* p = new int(42);
This is useful if you want a shared counter, for example in the implementation of shared_ptr<T>
.
Also, you are not forced to use new with classes in C++:
void function()
{
MyClass myObject(1, 2, 3);
}
This will allocate myObject
on the stack. Note that new
is rarely used in modern C++.
Furthermore, you can overload operator new
(either globally or class-specific) in C++, so even if you say new MyClass
, the object does not necessarily get allocated on the heap.
I don't know precisely about Java (and it seems quite difficult to get a documentation about it).
In C#, new
invokes the constructor and returns a fresh object. If it is of value type, it is allocated on the stack (eg. local variable) or on the heap (eg. boxed object, member of a reference type object). If it is of reference type, it always goes on the heap and is managed by the garbage collector. See http://msdn.microsoft.com/en-us/library/fa0ab757(v=vs.80).aspx for more details.
In C++, a "new expression" returns a pointer to an object with dynamic storage duration (ie. that you must destroy yourself). There is no mention of heap (with this meaning) in the C++ standard, and the mechanism through which such an object is obtained is implementation defined.
My understanding has always been, regardless of C++ or C# or Java, that when we use the
new
keyword to create an object it allocates memory on the heap.
Your understanding has been incorrect:
new
may work differently in different programming languages, even when these languages are superficially alike. Don't let the similar syntax of C#, C++, and Java mislead you!The terms "heap" and "stack" (as they are understood in the context of internal memory management) are simply not relevant to all programming languages. Arguably, these two concepts are more often implementation details than that they are part of a programming language's official specification.
(IIRC, this is true for at least C# and C++. I don't know about Java.)
The fact that they are such widespread implementation details doesn't imply that you should rely on that distinction, nor that you should even know about it! (However, I admit that I usually find it beneficial to know "how things work" internally.)
I would suggest that you stop worrying too much about these concepts. The important thing that you need to get right is to understand a language's semantics; e.g., for C# or any other .NET language, the difference in reference and value type semantics.
Example: What the C# specification says about operator new
:
Note how the following part of the C# specification published by ECMA (4th edition) does not mention any "stack" or "heap":
14.5.10 The new operator
The new operator is used to create new instances of types. […]
The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. In particular, instances of value types require no additional memory beyond the variables in which they reside, and no dynamic allocations occur when new is used to create instances of value types.
Instead, it talks of "dynamic allocation of memory", but that is not the same thing: You could dynamically allocate memory on a stack, on the heap, or anywhere else (e.g. on a hard disk drive) for that matter.
What it does say, however, is that instances of value types are stored in-place, which is exactly what value type semantics are all about: Value type instances get copied during an assignment, while reference type instances are referenced / "aliased". That is the important thing to understand, not the "heap" or the "stack"!
In c#, a class
always lives on the heap. A struct
can be either on the heap or stack:
- variables (except captures and iterator blocks), and fields on a struct that is itself on the stack live on the stack
- captures, iterator blocks, fields of something that is on the heap, and values in an array live on the heap, as do "boxed" values
Java 7 does escape analysis to determine if an object can be allocated on the stack, according to http://download.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html.
However, you cannot instruct the runtime to allocate an object on heap or on stack. It's done automatically.
Regarding c#, read The Truth About Value Types. You will see that value types can go on the heap as well.
And at this question is suggested that reference types could go on the stack. (but it does not happen at the moment)
(Referring to Java) What you said is correct- primitives are allocated on the stack (there are exceptions e.g. closures). However, you might be referring to objects such as:
Integer n = new Integer(2);
This refers to an Integer object, and not a primitive int. Perhaps this was your source of confusion? In this case, n will be allocated on the heap. Perhaps your confusion was due to autoboxing rules? Also see this question for more details on autoboxing. Check out comments on this answer for exceptions to the rule where primitives are allocated on the heap.
In Java and C#, we don't need to allocate primitive types on the heap. They can be allocated on the stack ( not that they are restricted to stack ). Whereas, in C++ we can have primitive as well as user defined types to be allocated on both stack and heap.
In C++, there's an additional way to use the new operator, and that's via 'placement new'. The memory you point it to could exist anywhere.
See What uses are there for "placement new"?
精彩评论