阿里架构师眼里JVM能够说的那些事

前言

对于C语言开发的程序员来讲,在内存管理方面,必须负责每个对象的生命周期,从有到无。java

对于Java程序员你来讲,在虚拟机内存管理的帮助下,不须要为每一个new对象都匹配free操做,内存泄露和内存溢出等问题也不太容易出现,不过也正是由于把内存管理交给了虚拟机,一旦运行中的程序出现了内存泄露问题,给排查过程形成很大困难。因此只有理解了Java虚拟机的运行机制,才可以指挥若定于各类代码。本文以HotSpot为例说说虚拟机的那些事。程序员

JAVA虚拟机把管理的内存划分为几个不一样的数据区。面试

clipboard.png

Java堆

Java堆是被全部线程共享的一块内存区域,主要用于存放对象实例,Java虚拟机规范中有这样一段描述:全部的对象实例和数据都要在堆上进行分配。为对象分配内存就是把一块大小肯定的内存从堆内存中划分出来,一般有两种方法实现:数组

1 、指针碰撞法性能优化

假设Java堆中内存时完整的,已分配的内存和空闲内存分别在不一样的一侧,经过一个指针做为分界点,须要分配内存时,仅仅须要把指针往空闲的一端移动与对象大小相等的距离。数据结构

二、空闲列表法多线程

事实上,Java堆的内存并非完整的,已分配的内存和空闲内存相互交错,JVM经过维护一个列表,记录可用的内存块信息,当分配操做发生时,从列表中找到一个足够大的内存块分配给对象实例,并更新列表上的记录。架构

对象建立是一个很是频繁的行为,进行堆内存分配时还须要考虑多线程并发问题,可能出现正在给对象A分配内存,指针或记录还未更新,对象B又同时分配到原来的内存,解决这个问题有两种方案:并发

一、采用CAS保证数据更新操做的原子性;分布式

二、把内存分配的行为按照线程进行划分,在不一样的空间中进行,每一个线程在Java堆中预先分配一个内存块,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB);

Java栈

Java栈是线程私有的,每一个线程对应一个Java栈,每一个线程在执行一个方法时会建立一个对应的栈帧(Stack Frame),栈帧负责存储局部变量变量表、操做数栈、动态连接和方法返回地址等信息。每一个方法的调用过程,至关于栈帧在Java栈的入栈和出栈过程。

clipboard.png

局部变量表 用于存放方法参数和方法内部定义的局部变量,其大小在代码编译期间已经肯定,在方法运行期间不会改变。局部变量表以变量槽(Slot)为最小存储单位,每一个Slot可以存放一个boolean、byte、char、shot、int、float、reference和returnAddress类型的32位数据,对于64位的数据类型long和double,虚拟机会以高位对齐的方式为其分配两个连续的Slot空间。

在方法执行时,若是是实例方法,即非static方法,局部变量表中第0位Slot默认存放对象实例的引用,在方法中能够经过关键字 this 进行访问,方法参数按照参数列表顺序,从第1位Slot开始分配,方法内部变量则按照定义顺序进行分配其他的Slot。

clipboard.png

对应的局部变量表以下:

clipboard.png

使用 javap -c 命令查看方法calc的字节码

clipboard.png

其中iload_1和iload_2分别从局部变量表中的第1位和第2位中加载数据。

方法区

方法区和Java堆同样,是全部线程共享的内存区域,用于存放已被虚拟机加载的类信息、常量、静态变量和即时编译器编译后的代码等数据。

运行时常量池是方法区的一部分,用于存放编译期间生成的各类字面常量和符号引用。

指令计数器

指令计数器是线程私有的,每一个线程都有独立的指令计数器,计数器记录着虚拟机正在执行的字节码指令的地址,分支、循环、跳转、异常处理和线程恢复等操做都依赖这个计数器完成。若是线程执行的是native方法,这个计数器则为空。

对象的内存布局

对象在内存中布局能够分红三块区域:对象头、实例数据和对齐填充。

一、对象头

对象头包括两部分信息:运行时数据和类型指针,若是对象是一个数组,还须要一块用于记录数组长度的数据。

1.一、运行时数据包括哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向锁ID和偏向时间戳等,这部分数据在32位和64位虚拟机中的长度分别为32bit和64bit,官方称为”Mark Word”。Mark Word被设计成非固定的数据结构,以实如今有限空间内保存尽量多的数据。

32位的虚拟机中,对象未被锁定的状态下,Mark Word的32bit中25bit存储对象的HashCode、4bit存储对象分代年龄、2bit存储锁标志位、1bit固定为0,具体以下:

clipboard.png

其它状态(轻量级锁定、重量级锁定、GC锁定、可偏向锁)下Mark Word的存储内容以下:

clipboard.png

1.二、对象头的类型指针指向该对象的类元数据,虚拟机经过这个指针能够肯定该对象是哪一个类的实例。

二、实例数据

实例数据就是在程序代码中所定义的各类类型的字段,包括从父类继承的,这部分的存储顺序会受到虚拟机分配策略和字段在源码中定义顺序的影响。

三、对齐填充

因为HotSpot的自动内存管理要求对象的起始地址必须是8字节的整数倍,即对象的大小必须是8字节的整数倍,对象头的数据正好是8的整数倍,因此当实例数据不够8字节整数倍时,须要经过对齐填充进行补全。

在互联网公司面试中,架构的底层必定是面试官会问到的问题,针对面试官通常会提到的问题,我录制了一些分布式,微服务,性能优化等技术点底层原理的录像视频,加群: 478030634 能够免费获取这些录像,里面还有些分布式,微服务,性能优化,Spring,MyBatis的等源码知识点的录像视频。这些视频都是我找一些资深架构师朋友一块儿录制出来的,这些视频帮助如下几类程序员:

1.对如今的薪资不满,想要跳槽,却对本身的技术没有信心,不知道如何面对面试官。

2.想从传统行业转行到互联网行业,但没有接触过互联网技术。

3.工做1 - 5年须要提高本身的核心竞争力,但学习没有系统化,不知道本身接下来要学什么才是正确的,踩坑后又不知道找谁,百度后依然不知因此然。

4.工做5 - 10年没法突破技术瓶颈(运用过不少技术,在公司一直写着业务代码,却依然不懂底层实现原理)

若是你如今正处于我上述所说的几个阶段能够加下个人群来学习。并且我也可以提供一些面试指导,职业规划等建议。

相关文章
相关标签/搜索