浅析JAVA中堆内存与栈内存的区别

Java把内存划分成两种:一种是栈内存,一种是堆内存。

一、栈内存

存放基本类型的变量,对象的引用和方法调用,遵循先入后出的原则。 栈内存在函数中定义的“一些基本类型的变量和对象的引用变量”都在函数的栈内存中分配。当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。

Java中的代码是在函数体中执行的,每个函数主体都会被放在栈内存中,比如main函数。假如main函数里调用了其他的函数,比如add(),那么在栈里面的的存储就是最底层是main,mian上面是add。栈的运行时后入先出的,所以会执行时会先销毁add,再销毁main。

栈的优势是,栈内存与堆内存相比是非常小的,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(int, short, long, byte, float, double, boolean, char)和对象句柄。栈有一个很重要的特殊性,就是存在栈中的数据可以共享。

二、堆内存

存放所有new出来的对象和数组 特此强调,堆内存和数据结构中的堆完全是两码事,分配方式倒是类似于链表 堆内存是区别于栈区、全局数据区和代码区的另一个内存区域。堆允许程序在运行时动态地申请某个大小的内存空间,堆内存实际上指的就是(满足堆内存性质的)优先队列的一种数据结构,第1个元素有最高的优先权。

在堆内存分配时首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。

另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。堆内存是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆内存的大小受限于计算机系统中有效的虚拟内存。由此可见,堆内存获得的空间比较灵活,也比较大。堆内存是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

栈与堆都是Java用来在Ram中存放数据的地方。与C ++不同,Java自动管理栈和堆,程序员不能直接设置栈或堆 Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过新的,newarray,anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

三、其他数据存储 1、常量池:存放基本类型常量和字符串常量(public static final) 2、静态域:存放静态成员(static定义的) 3、非RAM存储:硬盘等永久存储空间 堆内存和栈内存的区别: 1、应用程序所有的部分都使用堆内存,然后栈内存通过一个线程运行来使用。 2、不论对象什么时候创建,他都会存储在堆内存中,栈内存包含它的引用。栈内存只包含原始值变量好和堆中对象变量的引用。 3、存储在堆中的对象是全局可以被访问的,然而栈内存不能被其他线程所访问。 4、栈中的内存管理使用LIFO的方式完成,而堆内存的管理要更复杂了,因为它是全局被访问的。 5、栈内存是生命周期很短的,然而堆内存的生命周期从程序的运行开始到运行结束。 6、我们可以使用-Xms和-Xmx JVM选项定义开始的大小和堆内存的最大值,我们可以使用-Xss定义栈的大小 7、当栈内存满的时候,Java抛出java.lang.StackOverFlowError异常而堆内存满的时候抛出java.lang.OutOfMemoryError: Java Heap Space错误 8、和堆内存比,栈内存要小的多,因为明确使用了内存分配规则(LIFO),和堆内存相比栈内存非常快。

总结: 1 栈:为编译器自动分配和释放,如函数参数、局部变量、临时变量等等 2 堆:为成员分配和释放,由程序员自己申请、自己释放。否则发生内存泄露。典型为使用new申请的堆内容。 除了这两部分,还有一部分是: 3 静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。

来源:博客园 zsq_fengchen

本文分享自微信公众号 - java工会(javagonghui)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-01-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一英里广度一英寸深度的学习

MAT java 内存分析工具

https://www.eclipse.org/mat/downloads.php

66630
来自专栏Linux驱动

C-switch case之如何巧妙判断范围区域

52230
来自专栏Kurt Niu 的博客

记一次非常规方法对接硬件设备(Grason Stadler GSI 61)

厂家提供的自带软件是通过USB虚拟串口,每次程序启动传输是通过再次虚拟新的串口传输数据...所以我们无法捕获数据,更无法模拟客户端软件.

12520
来自专栏我是攻城师

一次ArrayList的使用不当导致线上jstorm任务启动失败的案例

最近一次的的项目版本迭代中,我们的jstorm项目里面增加了一些新的功能,开发完毕后,按照正常的上线流程,代码是需要在开发,测试和预发布环境,测试完毕后才能上线...

19620
来自专栏王磊的博客

Java提高班(六)反射和动态代理(JDK Proxy和Cglib)

反射和动态代理放有一定的相关性,但单纯的说动态代理是由反射机制实现的,其实是不够全面不准确的,动态代理是一种功能行为,而它的实现方法有很多。要怎么理解以上这句话...

23230
来自专栏along的开发之旅

ndkCompile ndk-build CMakeList 区别.

一直很好奇`android.useDeprecatedNdk = true`到底是使用的什么废弃ndk, 但是找资料一直没有找到相关的.

17920
来自专栏Java爬坑系列

你不可不知的Java引用类型之——ReferenceQueue源码详解

对于软引用、弱引用和虚引用,如果我们希望当一个对象被垃圾回收器回收时能得到通知,进行额外的处理,这时候就需要使用到引用队列了。

13630
来自专栏IT综合技术分享

第一章 第一节 postgresql安装与配置

本次安装环境为Ubuntu18.04 Server,postgresql采用10版本。

18450
来自专栏along的开发之旅

写OC遇到的一个超级低级错误:

AppCode提示: class method is called from instance context.

11840
来自专栏编程心路

语言小知识-Java LinkedList类 深度解析

上篇文章《ArrayList类 深度解析》中,我对 ArrayList 的源码做了翻译,这次再来翻译一下 LinkedList 类的,阅读完源码后提出下面的问题...

8720

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励