从里到外,手把手一起把JVM虚拟机整体结构与对象内存分配解析摸透透的,简单易懂!_一起摸一起透(1)

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

从里到外,手把手一起把JVM虚拟机整体结构与对象内存分配解析摸透透的,简单易懂!

JVM虚拟机整体结构解析

整体结构介绍

jvm整体分为:

  • -栈
  • 方法区
  • 本地方法栈
  • 程序计数器
栈 Stack

栈是JVM重要的组成部分,每有一个新的线程都JVM都会为其在栈上分配一份内存,线程里有栈帧,程序计数器。另外线程栈内存大小决定的线程数量的多少,当线程栈内存大小设置的越大,则同时存在的线程数量越少,反则越大。另外在栈中最容易发生的错误是StackOverflowError 栈溢出,看以下代码:

 public class StackOverflowTest { 
   static int count = 0;
    static void redo() { 
    count++; 
     redo(); 
     }
     public static void main(String[] args) { 
      try { 
    redo(); 
     } catch (Throwable t) { 
     t.printStackTrace(); 
     System.out.println(count); 
            } 
        } 
     }  
      运行结果:
      java.lang.StackOverflowError 


参数影响: -Xss 256KB(默认1M) 设置栈大小 栈的大小会影响count 的次数,-Xss设置的大小越大,count的次数也就越大,反之亦然.
【领取资料】

栈帧结构组成
  1. 局部变量表:主要用来保存声明的局部变量以及方法的参数信息,局部变量表作用于为当前方法,当方法执行完成后,局部变量表也会随之删除,释放内存。另外局部变量表里用来保存信息的叫做变量槽(slot)
类型占slot个数
byte1
short1
int1
long2
float1
double2
boolean1
char1

操作数栈:顾名思义,操作数栈其本质就是个栈,压栈,出栈两个操作,例如执行a+b,先将局部变量表中的a与b分别压入栈中,接着执行加法操作,最终出栈。

动态链接:是在程序运行期间完成的将符号引用替换为直接引用叫动态链接,既然有动态链接那么自然也有静态链接,部分符号引用在类加载阶段(解析)的时候就转化为直接引用,这种转化为静态链接。

方法返回地址:在方法退出(正常执行/异常返回)后,返回方法被调用的位置。

栈结构图

img

程序计数器(Program Counter Register)

程序计数器也叫PC寄存器是JVM非常重要的一个结构,是线程私有的,每个线程独有一份,它用来保存指向下一条将被执行指令的地址,例如当线程被阻塞再进行唤醒时,从程序计数器读取指令的地址,从而继续执行。
【领取资料】

本地方法栈 Native Method Stack

本地方法栈主要是为了执行native方法,保存native方法进入区域的地址,所以本地方法栈也是线程私有的内存区域。

方法区 Method Area(元空间 Meta Space)

被所有的线程共享。方法区包含所有的class和static变量,类的方法代码,变量名,方法名,访问权限,返回值,以及我们经常说的常量池运行时常量池都是在方法区的。

堆 Heap

堆是非常重要的一个区域,管理着几乎(不是所有)所有的对象,我们常说的垃圾回收的主要区域就是发生在这个区域。堆分为新生代(young)与老年代(Old),新生代又分为Eden与survivor区,survivor分为From区与To区。这几个区存放着java的对象,当区内存不够的时候会发生GC,GC主要分为两种,一种是minorGC(Young GC),另一种是Full GC,JVM调优主要根据代码调节JVM参数,从而减少Full GC的次数。

堆结构示意图

image.png

逃逸分析

首先大家听得最多的就是new 出来对象是存放在堆中的,但是在上文中,所写的是几乎对象是存在堆中,那么为什么是几乎呢,因为有的对象是存放在栈中的,是不是很不可思议,接下来来看下一段代码。

// 方法一
public Person test1() {
        Person person = new Person();
        person.setId(1);
        return person;
        } 
// 方法二 
public void test2() { 
         User person = new person(); 
         person.setId(1); 
       }

上述代码中很显然test1方法中的personr对象被返回了,那么这个对象就可能被其他方法进行引用,test2方法中的personr对象,当方法结束的时候,该对象就是一个无效对象了,不会在其他地方被进行引用,对于这样的对象,JVM将其分配的栈内存里,让其在方法结束时跟随栈内存一起被回收掉,减少堆内存的回收。 JVM对于这种情况可以通过开启逃逸分析参数(-XX:+DoEscapeAnalysis)来优化对象内存分配位置,JDK7之后默认开启逃逸分析,如果要关闭使用参数(-XX:-DoEscapeAnalysis)

对象内存分配

对象内存分配流程图

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

尝辄止,不再深入研究,那么很难做到真正的技术提升。**

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值