话不多说直接上才艺“来吧!展示,【高级 Java 架构师系统学习
对于 C 语言开发的程序员来说,在内存管理方面,必须负责每一个对象的生命周期,从有到无。对于 Java 程序员你来说,在虚拟机内存管理的帮助下,不需要为每个 new 对象都匹配 free 操作,内存泄露和内存溢出等问题也不太容易出现,不过也正是因为把内存管理交给了虚拟机,一旦运行中的程序出现了内存泄露问题,给排查过程造成很大困难。所以只有理解了 Java 虚拟机的运行机制,才能够运筹帷幄于各种代码。本文以 HotSpot 为例说说虚拟机的那些事。
JAVA 虚拟机把管理的内存划分为几个不同的数据区。
Java 堆
Java 堆是被所有线程共享的一块内存区域,主要用于存放对象实例,Java 虚拟机规范中有这样一段描述:所有的对象实例和数据都要在堆上进行分配。为对象分配内存就是把一块大小确定的内存从堆内存中划分出来,通常有两种方法实现:
1 、指针碰撞法假设 Java 堆中内存时完整的,已分配的内存和空闲内存分别在不同的一侧,通过一个指针作为分界点,需要分配内存时,仅仅需要把指针往空闲的一端移动与对象大小相等的距离。
2、空闲列表法事实上,Java 堆的内存并不是完整的,已分配的内存和空闲内存相互交错,JVM 通过维护一个列表,记录可用的内存块信息,当分配操作发生时,从列表中找到一个足够大的内存块分配给对象实例,并更新列表上的记录。
对象创建是一个非常频繁的行为,进行堆内存分配时还需要考虑多线程并发问题,可能出现正在给对象 A 分配内存,指针或记录还未更新,对象 B 又同时分配到原来的内存,解决这个问题有两种方案:1、采用 CAS 保证数据更新操作的原子性;2、把内存分配的行为按照线程进行划分,在不同的空间中进行,每个线程在 Java 堆中预先分配一个内存块,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB);
Java 栈
Java 栈是线程私有的,每个线程对应一个 Java 栈,每个线程在执行一个方法时会创建一个对应的栈帧(Stack Frame),栈帧负责存储局部变量变量表、操作数栈、动态链接和方法返回地址等信息。每个方法的调用过程,相当于栈帧在 Java 栈的入栈和出栈过程。
局部变量表?用于存放方法参数和方法内部定义的局部变量,其大小在代码编译期间已经确定,在方法运行期间不会改变。局部变量表以变量槽(Slot)为最小存储单位,每个 Slot 能够存放一个 boolean、b
yte、char、shot、int、float、reference 和 returnAddress 类型的 32 位数据,对于 64 位的数据类型 long 和 double,虚拟机会以高位对齐的方式为其分配两个连续的 Slot 空间。
在方法执行时,如果是实例方法,即非 static 方法,局部变量表中第 0 位 Slot 默认存放对象实例的引用,在方法中可以通过关键字 this 进行访问,方法参数按照参数列表顺序,从第 1 位 Slot 开始分配,方法内部变量则按照定义顺序进行分配其余的 Slot。
class test {
public int calc(int a, int b, String operation) {
operation = "+";
return a + b;
}
public void main(String args[]) {
calc(100, 200, "+");
}
}
对应的局部变量表如下:
评论