Java中的堆和栈

        在【函数】中定义的一些【基本类型的变量】和【对象的引用变量】都是在函数的【栈内存】中分配的。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会【自动】释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。
        【堆内存】用于存放由new创建的【对象和数组】。在堆中分配的内存,由【java虚拟机】自动垃圾回收器来管理。
        在【堆】中产生了一个数组或者对象后,还可以在【栈】中定义一个【特殊的变量】,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的【引用变量】,以后就可以在程序中使用栈内存中的引用变量,来访问堆中的数组或者对象。引用变量相当于为数组或者对象起的一个【别名】,或者代号。
        【引用变量是普通变量】,定义时在栈中分配内存,【引用变量在程序运行到作用域外释放】。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在的代码块之外,数组和对象【本身】占用的堆内存也不会被释放(注意,此时仅仅是引用变量被释放了),数组和对象在没有引用变量指向它的时候,才变成【垃圾】(垃圾就是指未回收的、之后不会再使用的对象)。虽然垃圾不会再被使用,但是仍然占着内存,在随后的一个【不确定】的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因!

  栈与堆都是Java用来在内存中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
  Java的堆是一个运行时数据区,类的对象从中分配空间。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
  栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量和对象句柄。

        栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:
   int a = 3;
   int b = 3;
        编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。
        接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。
        这时,如果再令a=4;那么编译器会重新搜索栈中是否有4这个值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。
        要注意这种数据的【共享】与两个对象的【引用】同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个引用变量修改了这个对象的内部状态,会影响到另一个引用变量。 

  按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的。
  静态存储分配是指在【编译时】就能确定每个数据目标在【运行时】刻的存储空间需求,因而在编译时就可以给他们分配【固定的】内存空间。这种分配策略要求程序代码中不允许有【可变数据结构】(比如可变数组)的存在,也不允许有【嵌套或者递归的结构】出现,因为它们都会导致编译程序无法计算准确的存储空间需求。
  栈式存储分配也可称为【动态】存储分配,是由一个类似于堆栈的运行栈来实现的。和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中【进入一个程序模块时】,必须知道该程序模块所需的数据区大小,才能够为其分配内存。和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。
  静态存储分配要求【在编译时】能知道所有变量的存储要求,栈式存储分配要求【在过程的入口处】必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处【都无法确定】存储要求的数据结构的内存分配,比如可变长度串和对象实例。堆由【大片】的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放。

演示代码

public class Test {
    public static void main(String[] args) {
        Person person = new Person("1");//在【堆内存】中初始化一个对象,然后在【栈内存】中创建一个变量person,并让person指向此堆内存中的对象
        Person newPerson = person;//在【栈内存】中创建一个新的变量newPerson,赋值的含义为:让newPerson指向person所指向的堆内存中的同一个对象
        newPerson.name = "2";
        System.out.println(person.name + "-" + newPerson.name);//2-2
        newPerson = new Person("3");//在【堆内存】中初始化一个对象,然后让newPerson指向此对象,此时person所指向的对象还是之前的那个对象
        System.out.println(person.name + "-" + newPerson.name);//2-3
    }
    public static class Person {
        String name;
        public Person(String name) {
            this。name = name;
        }
    }
}

堆和栈 内存分配 heap stack的更多相关文章

  1. 【转载】c++中堆、栈内存分配

    一.内存划分 1.栈区(stack)— 由编译器自动分配释放 ,存放函数参数值,局部变量值等.其操作方式类似于数据结构中栈.2.堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时 ...

  2. c++中堆、栈内存分配

    转自:https://blog.csdn.net/qingtingchen1987/article/details/7698415 一个由C/C++编译程序占用内存分为以下几个部分1.栈区(stack ...

  3. Java中堆内存与栈内存分配浅析

    Java把内存划分成两种:一种是栈内存,另一种是堆内存.在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间, ...

  4. 如何让对象只在堆或者栈中分配空间ANDC++禁止一个类被继承

    在开始之前先来分析一下C++中的new运算符和operator new之间的关联. new:指我们在C++里通常用到的运算符,比如A* a = new A或者调用带参数的构造函数;  对于new来说, ...

  5. jvm 虚拟机参数_栈内存分配

    1.参数 -Xss 指定线程最大的栈空间,整个参数也直接决定了函数可调用的最大深度 2.测试代码 private static int count; public static void addCou ...

  6. 从一个微型例子看“C/C++的内存分配机制”和“数组变量名与指针变量名”(转)

    C++的内存有五大分区:堆区.栈区.自由存储区.全局/静态存储区.常量存储区. 五个数据段:数据段.代码段.BSS段.堆.栈 内存分配方式有三种: 从静态存储区域分配.内存在程序编译的时候就已经分配好 ...

  7. 栈 堆 stack heap 堆内存 栈内存 内存分配中的堆和栈 掌握堆内存的权柄就是返回的指针 栈是面向线程的而堆是面向进程的。 new/delete and malloc/ free 指针与内存模型

    小结: 1.栈内存 为什么快? Due to this nature, the process of storing and retrieving data from the stack is ver ...

  8. Java中堆内存(heap)和栈内存(stack)的区别

    在Java代码中,常常会使用到这样的类的声明实例化: Person per = new Person(); //这其实是包含了两个步骤,声明和实例化 Person per = null; //声明一个 ...

  9. .NET的堆和栈01,基本概念、值类型内存分配

    当我们对.NET Framework的一些基本面了解之后,实际上,还是很有必要了解一些更底层的知识.比如.NET Framework是如何进行内存管理的,是如何垃圾回收的......这样,我们才能写出 ...

随机推荐

  1. android的padding和margin的区别

    android:padding和android:layout_margin的区别:padding是站在父view的角度描述问题,它规定它里面的内容必须与这个父view边界的距离. margin则是站在 ...

  2. 单例-b

    这个比较老了,是mrc 里面的 此例以模仿Apple官方文档的单例写出来的.但是一直有一个非常不明白的地方,就是alloc与allocWithZone:的重载中,为什么要return [[self c ...

  3. ALTER TABLE

    •ALTER TABLE (表名) ADD (列名 数据类型); •ALTER TABLE (表名) MODIFY (列名 数据类型); •ALTER TABLE (表名) RENAME COLUMN ...

  4. mysql中的group_concat函数的用法

    本文通过实例介绍了MySQL中的group_concat函数的使用方法,比如select group_concat(name) . MySQL中group_concat函数 完整的语法如下: grou ...

  5. java学习之关键字

    java语言当中的关键字,之所以存在,是为了告诉编译器如何解释一段有意义的代码段.比如说 /**需求:演示java中关键字存在的含义步骤:用class,public,static,void等说明什么是 ...

  6. (转载)PHP去掉转义后字符串中的反斜杠\函数stripslashes

    (转载)http://www.beijibear.com/index.php?aid=182 addslashes()函数主要是在字符串中添加反斜杠对特殊字符进行转义,stripslashes()则是 ...

  7. 数据结构(set):COGS 62. [HNOI2004] 宠物收养所

    62. [HNOI2004] 宠物收养所 ★★★   输入文件:pet.in   输出文件:pet.out   简单对比时间限制:1 s   内存限制:128 MB 最近,阿Q开了一间宠物收养所.收养 ...

  8. java实现版本号的比较

    之前比较客户端版本号,一直用的是String.compareTo,知道出现bug之后才明白了它的不完善地方.它的比较方式是按照字符串的比较来执行的,所以它有不正确的地方.举个例子,之前客户端版本号为: ...

  9. [Locked] Group Shifted Strings

    Group Shifted Strings Given a string, we can "shift" each of its letter to its successive ...

  10. winscp自动执行脚本

    我们经常使用WinSCP工具通过sftp协议上传获取文件,本文描述通过bat批量处理文件. 首先,我们打开dos命令窗口使用 cd \d :D\WinSCP 打开WinSCP安装目录 上传文件: wi ...