从底层本质上解析java是值传值还是引用传值

关于java是值传值还是引用传值,在网上找了半天发现网上对于这个问题没有一个合理的解释,特地写了这篇文章,希望能给这个问题一个正确的解释

这个问题涉及语言层次的设计问题,所以我会列出从底向上的的所有结构,这个结构的合理性将不言自明

关于汇编语言中的立即数和直接寻址

立即数通常是指在立即寻址方式指令中给出的数

MOV EAX, 33221100H

关于这句汇编语言是将 33221100H直接放入EAX这个通用寄存器中,只需要一步

(AX全称是Accumulator Register,累加寄存器,E是extend,是代表扩展到32位

MOV指令是将源操作数复制到目的操作数)

直接寻址是在指令格式的地址的字段中直接指出操作数在内存的地址

MOV EAX, [0x04]

这句汇编语句是将0x04这个内存的值去出来放入EAX这个通用寄存器中,需要根据0x04找到这段内存,再把这段内存里面的值取出来放入EAX寄存器中

可以发现立即数消耗的CPU时钟周期要比直接寻址少,立即数要更快一些

关于C++的string内存布局

为什么这个问题要从C++的string讲起呢,因为string其实在不同情况下在内存中的存储情况不一样

当存储字符小于22的时候

从底层本质上解析java是值传值还是引用传值_第1张图片

 当存储字符大于22的时候

从底层本质上解析java是值传值还是引用传值_第2张图片

如果要存储的字符串长度(strlen 而非 sizeof)小于等于 22,则直接存储在函数栈中;最后一个字节(地址最高处)存储字符串的实际长度

如果要存储的字符串长度超过 22,会另外分配堆内存空间存储字符串本身,栈内的 24 个字节空间另有他用:
将字符串在堆中的地址存储在 24 个字节的前 8 个字节;
中间 8 个字节存储字符串的长度;
最后 8 个字节:地址最高的字节固定为 0x80,剩余字节存储分配的堆空间大小

可以发现当字符数小于22个字节的时候,马上就能找到要的内容

当大于22字节的时候就需要地址跳转了,速度要比上面慢一些

这时候你发现为什么我举汇编语言的例子了

当小于22字节的时候相当于立即数,大于22字节的时候需要寻址了

到虚拟机的内存布局

从底层本质上解析java是值传值还是引用传值_第3张图片

在java或者C#语言的虚拟机中

基础类型 byte, boolean, short, char int, float, long double是存放在栈内存中的,例如123

对象是放在堆内存中的,栈中只放一级索引,也就是堆的引用(或者指针)

关于栈和堆的深层次理解

在计算机底层上面特别是在硬件结构上面

cpu有专门的栈指针寄存器和基址指针寄存器寄存器(esp,ebp)来操作栈,速度比堆更快

所以让栈其实充当着目录的职责,堆充当着内容的角色,堆上的内容都是需要二级跳转的

容量低的东西,例如基础类型直接就放在栈上面了

而容量大的东西就放在堆上面

另外C++是可以在栈上面分配内存的,可以看我前面的文章

详解C++三种new的使用方法(在栈上用new生成对象)_星空_MAX的博客-CSDN博客

java是值传值还是引用传值

直接拿java举两个例子

第一个例子

int A = 123;
int B = A;

这时候输出B,还是123 

从底层本质上解析java是值传值还是引用传值_第4张图片

 第二个例子

classT A = new classT;
classT B = A;

从底层本质上解析java是值传值还是引用传值_第5张图片

这个例子也适用于字符串,因为java的字符串本质上就是类

 这时候的B输出的classT还是A,因为它们指向的空间是一样的

本质上在栈上的是值传递,在堆上的是引用传递

你可能感兴趣的:(java,开发语言,jvm)