堆和栈的区别

1.从存储角度来看,堆内存主要用于存储实例对象和JRE classes,占内存用于存储基本类型变量和对象的引用

 

2.从存取速度来看,栈存取速度快,堆存取速度比较慢,因为要在运行时动态分配内存,存取速度较慢

 

3.从线程的角度来看,每个线程都有一个自己的JAVA栈,所有线程共享一个堆。在JVM中,内存被分为线程栈区和堆区

 

4.从GC看来,栈区GC比较频繁,堆区GC不频繁。

 

注:堆的结构为链表,堆会产生内存碎片。

  堆会产生内存泄漏:已分配的内存无法释放,积累就会形成

  栈可能回产生内存溢出

 

  递归:容易造成栈溢出

  JavaScript:容造成内存泄漏

 

5.内存查找规则

5.1取值时:

  所有变量都从栈里开始找

  如果栈里没有,试图补this

5.2方法调用规则:

  (1)增加隔板

  (2)传输this

  (3)传输参数

5.3调用结束时

  (1)删除所有的变量

  (2)传输返回值

  (30去掉隔板)

 

6.关于JAVA中String类以形参传递到函数里面,修改后外面引用不能获取到更改后的值(转https://www.cnblogs.com/ytjava/p/7360109.html)

String类的存储是通过final修饰的char[]数组来存放结果的。不可更改。所以每次当外部一个String类型的引用传递到方法内部时候,只是把外部String类型变量的引用传递给了方法参数变量。对的。外部String变量和方法参数变量都是实际char[]数组的引用而已。所以当我们在方法内部改变这个参数的引用时候,因为char[]数组不可改变,所以每次新建变量都是新建一个新的String实例。很显然外部String类型变量没有指向新的String实例。所以也就不会获取到新的更改。 
下面程序例子假定tString指向A内存空间,A内存空间存放了”hello”这个字符串,然后调用modst函数将tString引用赋值给了text引用,注意是引用。确实是传址,我们知道String是不可变的,任何进行更改的操作都会产生新的String实例。所以在方法里面text指向了B空间,B空间存放了”sdf” 字符串,但是这个时候tString还是指向A空间,并没有指向B空间。

 

 

两次输出结果都是:

 

 

7.java中对象作为方法的入参时,这个入参是否会在栈和堆中创建临时的对象

package com.entity;

public class RefDemo03 {

    public static void main(String args[]){ 
        Demo d1 = new Demo() ; 
        d1.temp = "world" ; 
        //打印word
        System.out.println("fun()调用前:" +d1.temp) ; 
        fun(d1) ; 
        //打印JAVA
        System.out.println("fun()调用:" + d1.temp) ; 
        Demo d3 = new Demo();
        //打印hello
        System.out.println("第二次new的对象"+d3.temp);
    }

    
    
    public static void fun(Demo d2){ //d2会不在栈中创建对象,并在堆中分配内存给d2使用?
        d2.temp = "JAVA"; 
    }

}
class Demo{
    String temp = "hello" ; 
}

输出结果为:

fun()调用前:world
fun()调用:JAVA
第二次new的对象hello

总结:

当new一个对象的时候,java在堆对对象分配内存,在栈中定义一个特殊的变量,这个变量的取值等于对象在堆内存中的首地址。因此,单对象入参的时候,d2也是在栈中定义一个保存内存首地址的变量而已,这个地址指向原先在堆中被分配的内存。因此,在方法中对对象的操作是直接操作原有的对象,而不会在堆中分配而外的内存。也就是d1和d2指向的是同一个内存地址

 

 

8.关于String类型的内存指引可参考:

https://www.cnblogs.com/iyangyuan/p/4631696.html

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-08-22 15:06  我爱si搬砖  阅读(158)  评论(0编辑  收藏  举报