Java堆内存与栈内存对比

news/2024/7/20 12:44:12 标签: java, 内存管理, 数据结构与算法

在数据结构中,堆和栈可以说是两种最基础的数据结构,而Java中的栈内存空间和堆内存空间有什么异同,以及和数据结构中的堆栈有何关系?

一、Java 堆存储空间

堆内存(堆存储空间)会在Java运行时分配给对象(Object)或者JRE的类。只要我们创建了一个对象,那么在堆中肯定会分配一块存储空间给这个对象。而我们熟知的Java垃圾回收就是在堆存储空间上进行的,用以释放那些没有任何引用指向自身的对象。任何在堆中分配的对象都有全局访问权限,而且可以从应用的任何地方被引用。

二、Java 栈存储空间

Java 栈存储空间用来供线程执行时使用。栈空间中包含特别的变量如:短生命周期和指向其他在堆中对象的引用。这里栈存储空间满足后进先出的顺序。当一个函数被调用时,会在栈中分配一块新的存储空间,用来存放函数的基本数据(【Java心得总结一】Java基本类型和包装类型解析)以及在函数中对其它对象的引用。一旦函数执行结束,存储空间就会被释放供下一个函数使用。

栈存储空间远远小于堆存储空间

三、举例

Memory.java

复制代码
 1 public class Memory {
 2  
 3     public static void main(String[] args) { // Line 1
 4         int i=1; // Line 2
 5         Object obj = new Object(); // Line 3
 6         Memory mem = new Memory(); // Line 4
 7         mem.foo(obj); // Line 5
 8     } // Line 9
 9  
10     private void foo(Object param) { // Line 6
11         String str = param.toString();  Line 7
12         System.out.println(str);
13     } // Line 8
14  
15 }
复制代码

下图展示了堆栈存储空间是如何存储基本类型、对象以及指向变量的引用

 程序执行过程:

  1. 一旦我们开始运行程序,它会将所有运行时类装载入堆存储空间。当程序运行至第一行main()函数,Java Runtime会为主函数线程分配栈存储空间。
  2. 我们在第二行创建了基本数据类型,所以它会被存储在主函数线程的栈存储空间;
  3. 因为我们在第三行创建了Object对象,它会在堆中被创建,并且栈空间中保存有指向它的引用。同理第四行创建Memory对象。
  4. 当我们在main()主函数第五行调用foo()函数时,在栈空间顶部会分配一块空间给foo()函数使用。因为Java是值传递(Java 为值传递而不是引用传递),在foo函数第六行中会有一个新的引用被创建指向堆中的Object对象
  5. 在第7行创建了一个字符串,它会被放在堆空间的字符串池中(String Poll),而且在栈空间中会保存一个指向它的引用
  6. 在第8行foo函数执行完毕,此时其栈空间会被释放
  7. 在第9行main函数执行完毕,栈中分配给main函数的空间会被释放。同时程序也在这一行执行完毕,因此Java运行时(Java Runtime)会释放所有内存空间并且终止程序的执行。

四、堆栈异同

  1. 堆存储空间可以被应用的任何部分使用,然而栈存储空间只能被对应的执行线程使用
  2. 一旦对象被建立,那么就会在堆中分配一段存储空间而栈空间中保留有对它的引用。栈空间中仅仅保存基本数据类型和指向堆中对象的引用变量
  3. 堆中存储的对象可以被全局访问,然而栈中存储的变量不能被其它线程(函数)访问
  4. 栈中的内存管理采用先进后出的(LIFO)的方式,然而在堆中内存管理会更为复杂,因为堆中的对象可以被全局使用。对存储空间被分为Young-Generation,Old-Generation等,这个我会在之后总结
  5. 栈存储空间是短生命周期的,然而堆存储要长的多
  6. 利用-Xms和-Xmx来指明JVM的堆初始空间和最大空间,利用-Xss来定义栈空间大小
  7. 当栈空间满了,Java运行时会抛出 java.lang.StackOverFlowError ,然而堆空间满了,抛出的是 java.lang.OutOfMemoryError: Java Heap Space 错误
  8. 栈空间相比较于堆空间是非常小的,又因为栈中使用最简单的先进后出(LIFO)原则,它是远远快于堆的。

参考:https://www.cnblogs.com/xltcjylove/p/4502859.html

转载于:https://www.cnblogs.com/stanljj/p/8494438.html


http://www.niftyadmin.cn/n/1472328.html

相关文章

Minikube之Win10单机部署

Kubernetes(k8s)是自动化容器操作的开源平台,基于这个平台,你可以进行容器部署,资源调度和集群扩容等操作。如果你曾经用过Docker部署容器,那么可以将Docker看成Kubernetes底层使用的组件,Kuber…

一对一关联

Hibernate中的一对一关联 Hibernate提供了两种一对一映射关联关系的方式: 1)按照外键映射 2)按照主键映射 下面以员工账号表和员工档案表(员工账号和档案表之间是一对一的关系)为例,介绍这两种映射关系,并使…

新手根据菜鸟教程安装docker,从No package docker-io available开始遇到的坑...

https://www.cnblogs.com/maodot/p/7654918.html 结果在最前,安装docker的命令如下: yum install -y epel-release yum install -y docker-io    #不稳定,经常经常经常快完成的时候中断yum install https://get.docker.com/rpm/1.7.1/cen…

opencv的基本数据结构(二)(转)

转自:原文链接,以下代码、图片、内容有点改动,只为转载不降低博客内容的可阅性,版权归原作者所有。 OpenCV中强大的Mat类型大家已经比较熟悉了。这里梳理一些在工程中其他经常用到的几种基本数据类型。包括: Vec …

重写override

重写又叫覆盖,就是将从父类继承下来的属性或方法重新“定义”——就是从新写。 但注意:子类覆盖父类的方法,虽然可以去调用父类的同名方法去完成一定的工作,但不是必须的。也有可能父类的该方法所执行的结果并不适合子类&#xff…

java 锁Integer等对象失败

在学习并发编程时,多个线程对同一个Integer对象进行操作时,我想当然的直接对这个Integer对象加锁。然而最终结果让我百思不得其解,加锁无效。 public class TestJoin {static A testA new A();public volatile static Integer t 0;public s…

GCD nyoj 1007 (欧拉函数+欧几里得)

GCD nyoj 1007 (欧拉函数欧几里得) GCD 时间限制:1000 ms | 内存限制:65535 KB难度:3描述The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written (a,b),is the largest divisor common to a and b,Fo…

awk使用方法与案例介绍

一、awk简介 awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各…