Java内存分配
其中在JVM虚拟机中
jvm的内存分为五个部分:
这个只是在JDK之前的JVM内存图
在JDK8开始:取消了方法区,增加了元空间,把原来的方法区的多种功能进行拆分,有的功能放在了堆空间中,有的放在了元空间
-
栈:方法运行时使用的内存,比如main方法运行,进入方法栈中执行
方法开始执行会进栈,执行完毕会出栈(栈是一种数据结构,具体去学数据结构)
-
堆:存储对象或数组,new创建的东西都存在堆内存中
new出来的东西都会在这个内存中开辟空间并且产生地址值
-
方法区:存储可以运行的class文件(jdk8开始将方法区拆解了,新增元空间,并且元空间存储可以运行的class文件)
-
本地方法栈:JVM在使用操作系统功能的时候使用,不需要了解
-
寄存器:给CPU使用,不需要了解
数组的内存图
举例:
public static void main(String[] args){
int[] arr=new int[2];
sout(arr);
sout(arr[0]);
sout(arr[1]);
arr[0]=11;
arr[1]=22;
sout(arr[0]);
sout(arr[1]);
int[] arr2={33,44,55};
sout(arr2);
sout(arr1[0]);
sout(arr2[1]);
sout(arr2[2]);
}
上述代码执行流程:
-
main方法压入栈内存中
-
执行int[] arr=new int[2];
具体执行:
在堆内存中创建数组空间并产生地址值
把这个地址值赋值给arr
-
执行代码sout(arr)此时是打印出了arr的地址值
-
执行代码sout(arr[0])通过arr找到数组在堆内存中的地址,通过[0]找到对应地址中对应的数据
-
sout(arr[1])同理
-
arr[0]=11;如果arr[0]找到堆内存中开辟的空间中的对应数值存放地点,并且给他赋值11
-
arr[1]=22同理
-
执行代码int[] arr2={33,44,55};虽然没有new但是实质还是在堆空间中创建内存
这俩个内存之间互不干扰
-
具体如下
注:如果是这种情况
public static void main(String[] args){
int[] arr=new int[2];
int[] arr2=arr;
//这个代表的是把arr的地址值赋值给arr2
//此时修改arr的内容同时arr2也会改变!因为arr2存储的只是地址值!!!
}
方法的内存图
方法调用的内存原理
public class Test{
public static void main(String[] args){
eat();
}
public static void eat(){
study();
sout("吃饭");
sleep();
}
public static void sleep(){
sout("睡觉");
}
public static void study(){
sout("学习");
}
}
方法被调用后就会进栈运行
当方法执行完毕后,方法会出栈,此时栈内开辟的变量也随着销毁
上面代码执行后如图
当所有方法进栈之后,就会开始执行了,执行完毕后会一个个出栈
对象内存图
-
一个对象的内存图
Student s=new Student();
- 加载class文件
- 声明局部变量
- 在堆内存中开辟一个空间
- 默认初始化or显示初始化(如果在类中给变量赋值了就加载显示初始化,否则加载默认初始化)
- 构造方法初始化
- 将堆内存中的地址值赋值给左边的变量
当main方法也出栈的时候,此时没东西指向堆内存。故会自动销毁
类中的方法是先在方法区中加载,然后随着顺序执行的时候。
调用该方法才进栈
- 两个对象的内存图
和一个对象的内存图区别就是,方法区只需要加载一次!堆内存new几次开辟几次
- 两个引用指向同一个对象
this的内存原理
thi作用:区分局部变量和成员变量
this本质:所在方法调用者的地址值
字符串相关底层原理
-
字符串存储的内存原理
-
直接赋值会复用字符串常量池中的字符串
串池中有才会复用,没有则会在串池中新建对应的字符串
-
new出来的不会复用,而是在堆内存中开辟一个新空间
-
-
==号比较的到底是什么
- 基本数据类型比较的是数据值
- 引用数据类型比较的是地址值
一般用equals方法来比较而不是==
-
字符串拼接的底层原理
-
等号右边没有变量
-
等号右边有变量
-
在jdk8之前
-
在jdk8之后
jvm会先预估字符串的长度,然后创建数组字符串,然后把数组变成字符串
综上!字符串不建议直接用+这样即使底层有优化但是还是很慢非常影响效率!一般用StringBuilder进行拼接
-
-
-
StringBuilder源码分析
- 默认创建一个长度为16的字节数组
- 添加内容长度小于16直接保存
- 添加内容大于16扩容!(原容量*2+2)
- 如果还是不够就以实际为准