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. OpenGrok的安装

    http://opengrok.github.io/OpenGrok/ Ubuntu环境下OpenGrok的安装及使用 http://www.linuxidc.com/Linux/2013-05/84 ...

  2. nav

    $(document).ready(function() { $(window).resize(function(){ var need=0; var ul_max_width = $(window) ...

  3. .net序列化和反系列化json与类型对象转换

    先添加程序集:  System.Web.Extensions(在 System.Web.Extensions.dll 中) 引用:using System.Web.Script.Serializati ...

  4. DB2 SQL RR/RS/CS/UR四个级别《转载》

    1.RR隔离级别:在此隔离级别下, DB2会锁住所有相关的纪录.在一个SQL语句执行期间,所有执行此语句扫描过的纪录都会被加上相应的锁.具体的锁的类型还是由操作的类型来决定,如果是读取,则加共享锁:如 ...

  5. 使用SSH代理上IPV6(使用SSH端口转发)

    这几个月在国外待着,一直担心我的六维账户怎么办,那可是个宝贝啊.我看网上说可以用六飞啊神马的在IPV6下上IPV6的网站,但是冒失现在六维封禁了非学校的IPV6地址,所以这些软件就不顶用了. 想到以前 ...

  6. UIAutomation识别UI元素

    MS UI Automation(Microsoft User Interface Automation:UIA)是随.net framework3.0一起发布的,虽然在如今这个几乎每天都有各种新名词 ...

  7. oracle审计

    Orcale审计机制研究 1.   设置审计 1.1.  查看审计状态 SQL>conn /as sysdba; 已连接 SQL>show parameters audit_trail; ...

  8. java dump

    注意,请不要被我误导,我没有看其他资料,这是我自己分析的,有些可能是不对的 "DestroyJavaVM" prio=6 tid=0x00316800 nid=0x448 wait ...

  9. Sublime Text 有哪些使用技巧

    1. 更改变量名的几种方法<img src="https://pic4.zhimg.com/d93cf0e8987e0117f3a3187cfe8e53fb_b.jpg&quo ...

  10. POJ 3436 ACM Computer Factory

    题意:   为了追求ACM比赛的公平性,所有用作ACM比赛的电脑性能是一样的,而ACM董事会专门有一条生产线来生产这样的电脑,随着比赛规模的越来越大,生产线的生产能力不能满足需要,所以说ACM董事会想 ...