Home  >  Article  >  Java  >  What is the difference between heap, stack and stack in Java? Introduction to the differences between heap, stack and stack in Java

What is the difference between heap, stack and stack in Java? Introduction to the differences between heap, stack and stack in Java

不言
不言forward
2018-11-20 15:54:252539browse

The content of this article is about the difference between heap, stack and stack in Java? The introduction to the differences between heap, stack and stack in Java has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Let me explain one thing before the official content begins. The stack we often call stack is the collective name for heap and stack. Heap is heap and stack is stack. Together they are collectively called stack. ;

1. Stack and heap are places used by Java to store data in Ram. Unlike C, Java automatically manages the stack and heap, and programmers cannot directly set the stack or heap.

#2. The advantage of the stack is that the access speed is faster than the heap, second only to the registers directly located in the CPU. But the disadvantage is that the size and lifetime of the data stored in the stack must be determined and there is a lack of flexibility. In addition, stack data can be shared, see point 3 for details. The advantage of the heap is that it can dynamically allocate memory size, and the lifetime does not need to be told to the compiler in advance. Java's garbage collector will automatically collect the data that is no longer used. But the disadvantage is that due to the need to dynamically allocate memory at runtime, the access speed is slow.

#3. There are two types of data types in Java.

One is the basic type (primitive types), there are 8 types in total, namely int, short, long, byte, float, double, boolean, char (note, there are no the basic type of string). This type of definition is defined in the form such as int a = 3; long b = 255L; and is called an automatic variable. It is worth noting that automatic variables store literal values, not instances of classes, that is, they are not references to classes. There is no class here. For example, int a = 3; where a is a reference pointing to type int, pointing to the literal value 3. The data of these literal values ​​are known in size and lifetime (these literal values ​​are fixedly defined in a certain program block, and the field values ​​disappear after the program block exits). For the sake of speed, they exist on the stack. .

In addition, the stack has a very important special feature, that is, the data stored in the stack can be shared. Suppose we define at the same time:

 int a = 3;
 int b = 3;

The compiler first processes int a = 3; first it will create a reference to the variable a on the stack, and then find out whether there is a literal value If the address of 3 is not found, open an address to store the literal value of 3, and then point a to the address of 3. Then process int b = 3; after creating the reference variable of b, since there is already a literal value of 3 on the stack, b will directly point to the address of 3. In this way, there is a situation where a and b both point to 3 at the same time.

#Special attention is that the reference of this literal value is different from the reference of the class object. Assume that the references of two class objects point to the same object at the same time. If one object reference variable modifies the internal state of the object, then the other object reference variable will immediately reflect the change. In contrast, modifying the value of a literal reference does not cause the value of another reference to the literal to also change. As in the above example, after we define the values ​​of a and b, we then set a=4; then, b will not be equal to 4, but still equal to 3. Inside the compiler, when it encounters a=4;, it will re-search whether there is a literal value of 4 on the stack. If not, it will re-open an address to store the value of 4; if it already exists, it will directly point a to this address. . Therefore, changes in the value of a will not affect the value of b.

The other is wrapper class data, such as Integer, String, Double and other classes that wrap the corresponding basic data types. All these types of data exist in the heap. Java uses the new() statement to explicitly tell the compiler that it will be dynamically created as needed at runtime, so it is more flexible, but the disadvantage is that it takes up more time.

4. String是一个特殊的包装类数据。即可以用String str = new String("abc");的形式来创建,也可以用String str = "abc";的形式来创建(作为对比,在JDK 5.0之前,你从未见过Integer i = 3;的表达式,因为类与字面值是不能通用的,除了String。而在JDK 5.0中,这种表达式是可以的!因为编译器在后台进行Integer i = new Integer(3)的转换)。前者是规范的类的创建过程,即在Java中,一切都是对象,而对象是类的实例,全部通过new()的形式来创建。Java 中的有些类,如DateFormat类,可以通过该类的getInstance()方法来返回一个新创建的类,似乎违反了此原则。其实不然。该类运用了单 例模式来返回类的实例,只不过这个实例是在该类内部通过new()来创建的,而getInstance()向外部隐藏了此细节。那为什么在String str = "abc";中,并没有通过new()来创建实例,是不是违反了上述原则?其实没有。

5. 关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:

(1)先定义一个名为str的对String类的对象引用变量:String str;

(2)在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象o,并 将o的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并返回o的地址。

(3)将str指向对象o的地址。

值得注意的是,一般String类中字符串值都是直接存值的。但像String str = "abc";这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用!

为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。

 String str1 = "abc"; 
 String str2 = "abc"; 
 System.out.println(str1==str2); //true

 注意,我们这里并不用str1.equals(str2);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,str1与str2是否都指向了同一个对象。 
结果说明,JVM创建了两个引用str1和str2,但只创建了一个对象,而且两个引用都指向了这个对象。

我们再来更进一步,将以上代码改成:

 String str1 = "abc"; 
 String str2 = "abc"; 
 str1 = "bcd"; 
 System.out.println(str1 + "," + str2); //bcd, abc 
 System.out.println(str1==str2); //false

 这就是说,赋值的变化导致了类对象引用的变化,str1指向了另外一个新对象!而str2仍旧指向原来的对象。上例中,当我们将str1的值改为"bcd"时,JVM发现在栈中没有存放该值的地址,便开辟了这个地址,并创建了一个新的对象,其字符串的值指向这个地址。

事实上,String类被设计成为不可改变(immutable)的类。如果你要改变其值,可以,但JVM在运行时根据新值悄悄创建了一个新对象,然 后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的,但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中,会带有一定的不良 影响。

再修改原来代码:

String str1 = "abc"; 
String str2 = "abc"; 
str1 = "bcd";  
String str3 = str1; 
System.out.println(str3); //bcd  
String str4 = "bcd"; 
System.out.println(str1 == str4); //true

str3这个对象的引用直接指向str1所指向的对象(注意,str3并没有创建新对象)。当str1改完其值后,再创建一个String的引用 str4,并指向因str1修改值而创建的新的对象。可以发现,这回str4也没有创建新的对象,从而再次实现栈中数据的共享。

我们再接着看以下的代码。

1 String str1 = new String("abc"); 
2 String str2 = "abc"; 
3 System.out.println(str1==str2); //false

创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。

1 String str1 = "abc"; 
2 String str2 = new String("abc"); 
3 System.out.println(str1==str2); //false

创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。 

以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。

6. 数据类型包装类的值不可修改。不仅仅是String类的值不可修改,所有的数据类型包装类都不能更改其内部的值。

7. 结论与建议:

(1)我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,我们创建了String类的对象str。担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向 String类的引用被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。因 此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为"abc"的String类。清醒地认 识到这一点对排除程序中难以发现的bug是很有帮助的。

(2)使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。这个思想应该是 享元模式的思想,但JDK的内部在这里实现是否应用了这个模式,不得而知。

(3)当比较包装类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==。

(4)由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。

栈(stack):是一个先进后出的数据结构,通常用于保存方法(函数)中的参数,局部变量. 
在java中,所有基本类型和引用类型都在栈中存储.栈中数据的生存空间一般在当前scopes内(就是由{...}括起来的区域).

堆(heap):是一个可动态申请的内存空间(其记录空闲内存空间的链表由操作系统维护),C中的malloc语句所产生的内存空间就在堆中.

In java, all objects constructed using new xxx() are stored in the heap. When the garbage collector detects that an object is not referenced, it will automatically destroy the object. Therefore, in theory, java There is no limit to the living space of the object in it. As long as there is a reference type pointing to it, it can be used anywhere.

In JAVA , there are six different places where data can be stored:

1. Register. This is the fastest memory area because it is located in a different place than the other memory areas - inside the processor. However, the number of registers is extremely limited, so the registers are allocated by the compiler according to needs. You have no direct control, nor can you feel any hint of the register's existence in the program.

#2. Stack. Located in general-purpose RAM, but supported by the processor via its "stack pointer". If the stack pointer moves downward, new memory is allocated; if it moves upward, that memory is released. This is a fast and efficient method of allocating storage, second only to registers. When creating a program, the Java compiler must know the exact size and lifetime of all data stored on the stack, because it must generate the appropriate code to move the stack pointer up and down. This constraint limits the flexibility of the program, so although some Java data is stored on the stack - especially object references, Java objects are not stored there.

3. Heap. A general memory pool (also exists in RAM) used to store all JAVA objects. The advantage of the heap being different from the stack is that the compiler does not need to know how much storage area to allocate from the heap, nor does it need to know how long the stored data will survive in the heap. Therefore, there is great flexibility in allocating storage on the heap. When you need to create an object, you only need to write a simple line of new code. When this line of code is executed, storage will be automatically allocated in the heap. Of course, this flexibility must be paid for with corresponding code. Storage allocation using the heap takes more time than storage using the stack.

#4. Static storage. "Static" here means "in a fixed position". Static storage stores data that exists while the program is running. You can use the keyword static to identify specific elements of an object as static, but the JAVA object itself is never stored in static storage space.

#5. Constant storage. Constant values ​​are usually stored directly within the program code, which is safe because they can never be changed. Sometimes, in embedded systems, the constants themselves are separated from other parts, so in this case, you can choose to put them in ROM

6. Non-RAM storage. If the data survives completely outside the program, then it can exist without any control of the program and can exist even when the program is not running.
In terms of speed, there is the following relationship:

##Register< Stack< Heap< Others

『The above paragraph is excerpted from "Thinking in Java"』

Here, we mainly talk about the relationship between the heap and the stack:

Heap: The heap is the heap, which is the so-called dynamic Memory, in which the memory can be recycled when not needed, to be allocated to new memory requests. The data in the memory is unordered, that is, there is no necessary positional relationship between the memory allocated first and the memory allocated subsequently. There can be no order of priority. Generally, it is freely allocated by the user. Malloc allocates the heap and needs to be released manually.

Stack: It is STACK. In fact, it is a queue with only one entrance and exit, that is, First In Last Out (First In Last Out). The memory allocated first must be released later. Generally, it is automatically allocated by the system to store the parameter values ​​​​of the function, local variables, etc., and is automatically cleared.

Also, the heap is global, the stack is divided into a small piece when each function enters, and is released when the function returns. Static and global variables, variables obtained by new, are placed on the heap, and local variables are placed on the stack, so when the function returns, all local variables are gone.

In fact, in actual applications, the stack is mostly used to store method calls. The heap is used for object storage.

The basic types in JAVA actually require special treatment. Because, in JAVA, objects created through new are stored in the "heap", so using new to create a small, simple variable, such as a basic type, etc., is often not very efficient. Therefore, in JAVA, the same methods as C and C are used for these types. In other words, instead of using new to create, create an "automatic" variable that is not a "reference". This variable owns its "value" and is placed on the stack, making it more efficient.

The above is the detailed content of What is the difference between heap, stack and stack in Java? Introduction to the differences between heap, stack and stack in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:cnblogs.com. If there is any infringement, please contact admin@php.cn delete