zoukankan      html  css  js  c++  java
  • Java 栈与堆简介

    一、前言

      长久以来,一直被Java的内存分配问题,堆和栈问题困扰好久,面试的时候也非常心虚,这几天好好通过看书和技术博客来整理了一下,希望能找到我自己的理解方式。

    二、内存

      内存分物理内存和虚拟内存,物理内存也就是Ram,OS通过进程来运行程序,进程会向OS申请空间来运行,每个进程都拥有独立的一段地址空间,每个进程不会相互重合,操作系统也会保证每个进程只能访问自己的内存空间。

      jvm显然是属于OS的一个进程,其实我们这里可以把jvm当作是java世界中操作系统,运行java程序后生成的每一个线程都看作进程,那么和上面一样,每一个线程都需要内存空间来运行。而线程则将分配到的内存空间分为两种:堆和栈。

    三、栈

      java中的栈总是和线程关联在一起的,每创建一个线程时,jvm同时会为这个线程创建一个对应的栈,在栈中又会含有多个栈帧。

      这里首先有一点我们要清楚,就是栈这种数据结构的特点:后进先出,也就是栈顶的元素才能被push和pop,形象点来讲,就是http://stackoverflow.com/的那个Favicon

      明白这点之后,我们继续来看,每一个栈帧(我们这里统称为‘元素’好了),对应没个线程运行到的方法,每运行一个方法,就创建一个栈元素,每个栈元素会有一些内部变量(也就是方法内部定义的变量),操作栈,和方法返回值等信息。

      每当一个方法执行完成时,这个元素就会pop出栈作为这个方法的返回值,并清除这个元素,那么同时栈顶的元素就变为刚才元素的下一个元素活动了,对应来说就是运行到下一个方法。前面有提到操作栈,它只能操作当前元素的本地变量、传入参数和它调用的方法的返回值。如果在这个元素对于的方法中调用了另外一个方法,那么就会创建新的元素push到栈顶,变为当前活动元素。

      由于每一个线程创建一个栈,所以栈不是线程共享的,也就不用关心线程同步问题。

    四、堆

      堆是存储java对象的地方,也就是new出来的对象,每一个存储在堆中的java对象都是这个对象类的一个副本,它会复制包括继承自它父类的所有非静态属性(static属性不需要new也可以直接调用)。

      堆是java所有线程共享的,需要注意线程同步问题。

    五、联系

    1 public void doSomething(){
    2   String str1 = "abcd";
    3   String str2 = new String("1234");
    4   System.out.println(str1);
    5 }

      1.如上,当程序运行到这个方法的时候,就会创建一个栈元素。

      2.堆里面存放的是abcd字符串,栈里存放的是str1,str1的值是abcd在堆中的地址。str2同理。

      3.当这个方法执行结束时(超出变量的作用域),存放在栈中的和这个方法对应的元素会pop出栈,str1的内存空间会被马上释放,尽管str1被释放后,abcd没有被任何人所引用,但是堆中的abcd还是不会马上释放,而是后随后的一个不确定的时间里,被GC回收。打个比方,你在野外掉在一个枯井里,这时过来一个人发现了你,他是这个世界上唯一知道你所在的人,如果他在去找人来救你的路上死掉了,意味着你虽然不会马上也死掉,但是一定会在未来的某一个时间里死掉。(┬_┬)

    六、总结

      堆像是一个实打实的仓库,栈像是一本记事本。

      堆里存放的是真正的物品,栈里放的是物品在仓库里的地址。

      堆的分配和销毁效率低,栈的push和pop效率高。

      堆偏向于名词,栈偏向于动词。

      堆的对应单位是一个java应用程序,栈的对应单位是一个线程。

      堆是想要什么拿什么,栈是先进后出。

    七、题外话

    复制代码
    1         String str1 = "abcd";
    2         String str2 = "abcd";
    3         System.out.println(str1 == str2); 
    4 
    5          
    6       String str1 = new String("abcd");
    7         String str2 = new String("abcd");
    8         System.out.println(str1 == str2); 
    复制代码

      如上,输出的是true和false。

      在第一句执行完成之后,在堆中有个abcd对象(假设之前堆中没有abcd这个对象),在栈中有个str1的本地变量指向它。

      在第二句执行时,jvm会直接在堆中找是否已经存在abcd对对象,如果存在则直接将地址给str2,以防止重复创建一样的对象浪费内存。

      这种情况适用于所有基本类型变量(以及如上所示的String)。

      第二中情况下,由于两者都是new出来的,所以在内存中都各自分配内存。

      这种情况适用于所有object类型。

    转载人家抛弃的地址上的。

  • 相关阅读:
    3. 23 模拟面试
    3.15 模拟面试
    C++ 浅谈virtual
    3.6 模拟面试
    为s5pv210烧录镜像
    HISI VENC 实际输出帧率控制
    live555 交叉编译移植到海思开发板
    雄迈取流
    面试官吐槽:“软件测试员就是不行!”网友:我能把你面哭了!——软件测试笔试面试题目完全汇总
    “女人~,你在玩火”一个有磁性的声音说道——常用自动化测试工具
  • 原文地址:https://www.cnblogs.com/itcui/p/5684395.html
Copyright © 2011-2022 走看看