Java笔记:观念厘清-stack及heap的差异

本篇为记录不同的Java资料型态在记忆体中的变化情形,参考JVM 的 Stack 和 Heap并重点摘要。

Java语言中,资料型别分为基本型别参考(类别)型别2种,特性如下:

基本型别:byteshortintlongfloatdoublebooleanchar

特性

  1. 长度及生命周期都为可知 (程序码区块执行完变成GG)。
  2. 运算速度快,但长度与内容受限。

类别型态(或称参考型态):Class Type ( Reference Type)

不属於基本型别的,都属於此类别,这种类型通常都需要用 new 去创建,如 User user = new User("Mark"); 。
特性

  1. 因为是在执行时才会创建,所以长度及生命周期都不可预知。
  2. 灵活但运算较耗时。

https://ithelp.ithome.com.tw/upload/images/20220123/20143762O0RZ7YLC0a.png

stack:

  1. 用来储存函数路径区域变数
  2. Primitive Type,在 Stack 内的变数值为实际值,如上图变数a123
  3. 函数路径:Stack 内的变数值为物件实体在 Heap 中回传所在的记忆体位址,如上图的0x1234。
  4. 後进先出 (FILO) 的容器,具有存取速度快和管理简单的特点。
  5. 堆叠顺序:先宣告的变数,值在最下面,由下往上堆,如图b在a上面。
  6. 因为所存放的资料生命周期都是规律的(区域变数只能存在methods中),所以由系统自行去产生和回收空间即可,不用特别设计垃圾回收机制。

heap:

  1. Heap 内找一块区域放置物件实体属性资料,如图中的name :Mark,并产生位址:0x1234
  2. 在 Heap 创建完成後才会回传所在的记忆体位址stack
  3. 如果在类别中宣告的实体变数,没有立即给值的情况下,也是要等new一个该类别的物件实体,才会在heap中建立该物件的值,并把预设值存放进去,之後再把记忆体位址stack
  4. 存放的是共享资料,所以同 Process底下的其他 Thread 也可以进行存取。
  5. JAVA针对heap有 Garbage Collection 机制,因为无法掌握物件实体的生命周期,所以存取速度慢,但是GC是否有提升效能的部分还是有待讨论。


延伸:

两个物件实体:当a物件 = b物件,代表b物件在stack中只是把heap的位址给a物件。
两个区域变数:a = b,代表区域变数b在stack中把区域变数a的值给覆盖
运作如下图

https://ithelp.ithome.com.tw/upload/images/20220126/20143762L2gsP6M9J6.png

当在heap中没被参考到的物件,也就是没有变数储存他的位址(如上图0x12),就由JVM的GC机制回收并释放记忆体空间。


当方法的参数使用基本型别跟类别型别的差异:

	static void passValue(double value) {
		value = 20.0;
	}
	
	static void passReference(Pen reference) {
		reference.price = 20.0;
	}
	
	public static void main(String[] args) {
		double price = 10.0;
		passValue(price);
		System.out.println(price);        // 10
		
		Pen myPen = new Pen();
		myPen.price = 10.0;
		passReference(myPen);
		System.out.println(myPen.price);  // 20
	}

解:
当资料为基本型别时:

  1. 在stack会建立price 值为10.0的空间。
  2. 当方法passValue调用该值成为该方法的参数时,会在stack再建立一个空间储存该参数(value)的值10.0
  3. 在方法里面的区域变数value被赋予新的值20.0
  4. 方法passValue运作结束,区域变数value的生命周期也结束了。
  5. main方法的price还是一样没有变化为10.0

当资料为类别型别时:

  1. 在heap会建立属性price 值为10.0的空间,并回传位址0x12给stack并储存在变数myPen
  2. 当方法passReference调用该值(位址0x12)成为该方法的参数时,会在stack再建立一个空间储存该参数(reference)的值0x12
  3. 在方法里面的区域变数reference的属性price 值在heap中会被更改为20.0
  4. 方法passReference运作结束,区域变数reference的生命周期也结束了。
  5. main方法的myPen因为属性price 的值在heap中已经被更改为20.0,所以最後print出来的值就变为20.0。

https://ithelp.ithome.com.tw/upload/images/20220126/20143762dP4SuIOn0r.png

参考资料:
JVM 的 Stack 和 Heap:https://blog.marklee.tw/java-interview-jvm-stack-heap/


<<:  Jupyter Notebook 输入栏位设计(1)

>>:  Java:观念厘清(新手用)-单元运算子a++与++a的差异

DAY9 Linebot 自动回应-2

先检查一下你的专案结构是不是大概长成这样,有一些是後来才新增的功能。 假设原本我们安装的ngrok放...

DAY3 MongoDB 连线与 IDE

DAY3 MongoDB 连线与 IDE MongoDB 的连线方式主要有三种,分别是: legac...

追求JS小姊姊系列 Day20 -- 工具力,原来如此:继承。

前情提要: 在上一集解释了工具力的来源 方函式:还记得之前提到的建构式模式吗? 只要提供一个原型,就...

Eloquent ORM - 一对多关联

接着要来给 Todo 加上与 User 的关联,区分各 User 建立的 Todo。 一个 User...

[Day 13] 阿嬷都看得懂的基础 CSS 选择器

阿嬷都看得懂的基础 CSS 选择器 小孩子才做选择,我全都要! -民明书房《我那被限制住的想像》 昨...