jvm内存结构

Java虚拟机

    Java虚拟机运行时数据区域被分为五个区域:堆(Heap)、栈(Stack)、本地方法栈(Native Stack)、方法区(Method Area)、程序计数器(Program Count Register)。

·方法区(线程共享)

    类信息、构造函数、对象类型信息和普通方法的字节码内容、常量池和静态变量存储在该位置,方法区和堆一样都是运行时内存区域线程共享的;

·JAVA堆(线程共享)

   new出来的类对象、数组和大部分非静态成员变量存储在该位置,java堆同样是线程共享的,操作共享区域的成员就有了锁和同步,而且它的生命周期是和虚拟机一样的;JVM将堆分为新生代和老年代,而在新生代中又可以分为Eden与Survivor两部分,两者默认呈4:1的比例分配内存,而在survivor中又可分为两部分;当在新生代执行了GC后存活的对象,会进入survivor的to space区域,如果达到一定限制仍存活,则进入老年代。(在物理内存中,java堆结构并不是一块连续的空间,它仅仅是逻辑上的连续)

·JAVA栈(线程私有)

    描述的是Java方法执行时的内存模型;进程的执行单元是线程,每个线程执行的逻辑方法中定义的局部变量或引用变量均保存在该位置,因为调用的方法可能重名,所以为保证线程安全,jvm按照线程分配栈空间,一个线程对应一个java栈,当一个线程调用一个方法时,会向java栈中压一个元素,这个元素的就是“栈帧”,而该方法可能还会调用另一个方法,所以该线程就会再压一个栈帧直到不再递归调用方法时停止压栈(要注意这样会导致栈空间溢出),栈帧存储着类方法中的局部变量和中间状态的操作数等,java栈是线程私有的,而且它的生命周期和线程是同步的

如下图所示:一个线程一个栈,栈内又分为多个部分

 

·本地方法栈

    保存了本地方法,它是当程序调用类库(本地方法)中的方法时才会用到它

·PC计数器(线程私有)

    因为执行的是字节码,所以为了有序执行就用到了PC计数器,它是当前线程执行字节码的行号指示器。在多线程中,为了让每个线程切换回来后能够恢复原来执行的指令,就需要为每个线程启动一个PC计数器,这些计数器之间是互补影响的,因为PC计数器和栈一样都是线程私有的。(PC计数器是jvm唯一个不会出现内存溢出的组件)

java中变量存储位置:

定义成员变量:

int a=1;

a是基本数据类型且为非静态变量,所以存储在堆中

static int b = 2;

b为静态变量存储在方法区的静态区

String s = "abc"

s是成员变量的引用所以它存储在类对象所在的堆中,而此处的“abc”要存储在方法区的常量池。

定义局部变量

int i =1;

i是基本数据类型且是局部变量,所以存储在栈中

String st = new String(“hello”);

st是对象的引用应当存储在java栈中,而使用new关键字或者构造器创建的“hello”对象要存储在堆中;

简述栈和堆的差异

从存放数据来看:

   栈存放的是基本数据类型和引用变量;堆存放的是new对象和数组;栈中的引用变量大小在32位,基本数据类型变量在1-8字节,但是对于堆的话,他具有动态性,在运行时动态分配内存。

从数据共享来看:

   栈中的引用变量可以指向同一个地址空间,而堆中的数据是使用new关键字创建的,所以它们的地址空间均不同。

JVM执行流程:

    java源文件-->使用编译器编译成.class文件-->将字节码信息加载到方法区,并生产Class对象用于访问类的各种信息。-->基本语法、格式等验证-->初始化工作-->进入main主方法-->逐行执行命令,若遇到方法时创建栈帧压入栈顶。(依次循环直至退出main方法)-->垃圾回收(虚拟机管理并不一定最后进行回收)

编译的大致过程:

 

未完待续...

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值