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类型。
转载人家抛弃的地址上的。
Java 栈与堆简介的更多相关文章
- java栈内存堆内存和GC相关
java栈内存堆内存 Java把内存分成两种,一种叫做栈内存,一种叫做堆内存,有着不同的作用.栈内存用来存储局部变量和方法调用.栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属 ...
- Java栈与堆 (转)
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取速度比堆要快,仅次于直接位于C ...
- java栈、堆
一.栈.堆 几个小概念 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的 ...
- java栈与堆
java基本类型: 变量存放在栈区 java引用类型: 变量名存放在栈区,变量内容存放在堆区. 实例一: int a = 6; int b = 9; swap(int x, int y) { int ...
- Java栈和堆的区别
一.栈空间 1.栈空间存储数据效率高 2.栈中的数据是按“先进后出”的方式管理 3.栈空间存储空间比较小,不能存放大量的数据 4.JVM将基本类型的数据存放在栈空间 帮助理解 1.“客栈” 能提供很多 ...
- java栈和堆区别
1, 垃圾回收机制仅仅作用于堆内存,与栈内存无关; 2, 栈:stack 栈的存取速度比堆快,效率高 保存局部变量和对象的引用值 3, 堆:保存较大的变量 4, 栈有一个很重要的特殊性,就是存在栈中的 ...
- Java栈与堆一篇好文
http://blog.csdn.net/zhangao0086/article/details/6347342
- java 栈和堆
- JAVA基础-栈与堆,static、final修饰符、内部类和Java内存分配
Java栈与堆 堆:顺序随意 栈:后进先出(Last-in/First-Out). Java的堆是一个运行时数据区,类的对象从中分配空间.这些对象通过new.newarray.anewarray和mu ...
随机推荐
- 软件官网与memcached介绍
常见官网 http://www.keepalived.org http://nginx.org/ documentation 模块说明 http://www.apache.org/ https://o ...
- nfs之脚气
nfs工作模式参考 一.NFs是什么 NFS是Network File System的缩写,即网络文件系统.客户端通过挂载的方式将NFS服务器端共享的数据目录挂载到本地目录下. nfs为什么需要RPC ...
- python redis 发布订阅 实现 RPC同步
工作中用到的场景是,python主程序发布消息到Redis,然后停住等待Redis上订阅的Response.等待过程是阻塞的,相当于把异步通信封装成同步通信,类似于Java的RPC. RPC封装的代码 ...
- 【洛谷】P1892 团伙(并查集)+ 求助
题目描述 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋友: 我敌人的敌人也是我的朋友. 两个强盗是同一团伙的 ...
- jmeter4.0脚本录制
Jmeter录制脚本有两种方式.1.通过第三方工具录制比如:Badboy,然后转化为jmeter可用的脚本:2.使用jmeter本身自带的录制脚本功能. 本次使用jmeter本身自带的录制脚本功能 ...
- fatal error C1010: 在查找预编译头时遇到意外的文件结尾 (转)
错误描述:fatal error C1010: 在查找预编译头时遇到意外的文件结尾.是否忘记了向源中添加“#include "stdafx.h"”? 错误分析: 此错误发生 ...
- ffmpeg源码分析一:概述 (转1)
原帖地址:http://blog.csdn.net/austinblog/article/details/24800381 首先先看ffmpeg.c文件,有类似于如下的一些变量: InputStrea ...
- 搭建Git Server - Centos+Gitosis
参考并部分转载自:http://www.pfeng.org/archives/757 1. 安装依赖 yum -y install curl-devel expat-devel gettext-dev ...
- Linux下Spark框架配置(Python)
简述 Spark是UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用并行框架,Spark,拥有Hadoop MapReduce所具有的优点:但不同于MapRedu ...
- java 蓝桥杯基础训练 回文数
public class _8回文数 { //两种方法都可以 // public static void main(String[] args) { // String zheng ="&q ...