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. Python使用纯真年代数据库qqwry.dat转换物理位置

    PS:网上直接找的,贴出来,方便以后随时用,感谢分享的人. #!/usr/bin/python #encoding: utf-8 import socket import codecs import ...

  2. SharePoint 2010 产品六大功能模块

    对IT专业人员来说,新的产品,意味着新的功能,IT生产力提高的契机,更加关心如何使用新产品投入更少,产出更多.在本文中我们通过对SharePoint 2010产品的功能介绍.管理中心新功能介绍.系统新 ...

  3. Swordfish

    zoj1203:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1203 题意:给定平面上N个城市的位置,计算连接这N个城市所 ...

  4. #include< >和#include""的区别

    Answer 1:#include 会将指定文件的内容插入到源程序文件中.当使用的格式时,编译器会从环境变量INCLUDE所指定的路径中寻找file-name 文件,如果没有定义INCLUDE,C 编 ...

  5. Linux kernel ‘fib6_add_rt2node’函数安全漏洞

    漏洞名称: Linux kernel ‘fib6_add_rt2node’函数安全漏洞 CNNVD编号: CNNVD-201307-265 发布时间: 2013-07-16 更新时间: 2013-07 ...

  6. github上排名靠前的java项目之_storm

    1.和hadoop的比较 Storm: 分布式实时计算,强调实时性,常用于实时性要求较高的地方 Hadoop:分布式批处理计算,强调批处理,常用于数据挖掘.分析   2.Hadoop是实现了mapre ...

  7. HDOJ(HDU) 2139 Calculate the formula(水题,又一个用JavaAC不了的题目)

    Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) 看到这个时间,我懵逼了... 果然,J ...

  8. 搜索——[HAOI2012]添加号

    题目:[HAOI2012]添加号 描述: [题目描述] 有一个由数字1,2,…9组成的数字串(长度不超过8),问如何将M(M<=5)个加号"+"插入到这个数字串中,使所形成的 ...

  9. 九度online judge 1543 二叉树

    题目1543:无限完全二叉树的层次遍历 时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:389 解决:54 题目描述: 有一棵无限完全二叉树,他的根节点是1/1,且任意一个节点p/q的左儿 ...

  10. MyBatis(6):MyBatis集成Spring事务管理(下)

    前一篇文章复习了MyBatis的基本使用以及使用Spring管理MyBatis的事务的做法,本文的目的是在这个的基础上稍微做一点点的进阶:多数据的事务处理.文章内容主要包含两方面: 1.单表多数据的事 ...