Java内存区域和内存模型

Java内存区域
    Java虚拟机在运行时会将它所管理的内存划分为若干个不同的数据区域。有的区域随着虚拟机的启动而存在,有的则依赖用户的线程的启动和结束而建立和销毁。下面先看一网上的图,将的蛮好。


    按照上面的划分,一共可以分为两类,7个组成部分。一类是所有线程共享的数据区,他们随着虚拟机的启动而启动。一类是依赖线程的存在而存在。

1、程序计数器

        程序计数器是一块较小的内存空间,它可以看作当前线程所执行的字节码的行号指示器。通俗的将就是指示程序运行到哪了。

        Java虚拟机的多线程就是通过线程的轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(或者一个内核)都只会执行一条线程中的指令。为了线程切换后内回到正确执行的位置,每条线程都需要一个独立的程序计数器,各线程之间的程序计数器私有,互不影响。

2、虚拟机栈

        与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量、操作数栈、动态链接、方法出口等信息。有时候也把虚拟机栈笼统的划分为“栈”。

        这也就是说,当虚拟机调用一个java方法时,该方法会被压入线程的虚拟机栈的栈帧。但是,栈帧的压入和弹出都是需要消耗时间和内存的,影响性能。从这我们也可以看出,并不是将方法分的越细越好。


3、本地方法栈

       本地方法栈与虚拟机所发挥的作用非常相似。虚拟机栈为虚拟机执行Java方法(也就是字节码)的服务,而本地方法栈则为虚拟机使用到的Native方法服务。

4、Java堆

    Java堆是Java虚拟机中所管理的内存最大的一块。Java堆是被所有线程共享的一块区域,在虚拟机启动的时候创建。此区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

    Java堆是垃圾收集管理的主要区域,由于现在收集器基本都采用分代收集方法,所以Java堆中还可以分为新生代,老年代,永久代。1.8之后取消了永久代;其中新生代又划分为Eden空间,From Survivor空间,To Survivor空间。无论怎么划分都是为了更好的回收,分配,利用内存。从内存分配的角度看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区。

    根据虚拟机的规定,Java堆可以处于物理上不连续的内存空间,只要逻辑上是连续即可。

5、方法区

    方法区和Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量(final)、静态变量(static)、即使编译器(JTI)编译后的代码等数据。

6、常量池

    常量池其实不用单独列出来将,常量池作为方法区的一部分,存放的是编译器生成的各种字面常量和符号引用,这部分内容将在类加载进入方法区的运行时常量池中存放。

7、总结

    Java虚拟机规范把方法区描述为堆的一个逻辑部分,其实Java虚拟机栈和程序计数器可以看成指令部分;方法区存储一些不会变更的数据。


Java内存模型


    Java内存模型(即Java Memory Model,简称JMM)本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),用于存储线程私有的数据,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝的自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,工作内存中存储着主内存中的变量副本拷贝,前面说过,工作内存是每个线程的私有数据区域,因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成。


    需要注意的是, JMM与Java内存区域的划分是不同的概念层次,更恰当说JMM描述的是一组规则,通过这组规则控制程序中各个变量在共享数据区域和私有数据区域的访问方式,JMM是围绕原子性,有序性、可见性展开的(稍后会分析)。JMM与Java内存区域唯一相似点,都存在共享数据区域和私有数据区域,在JMM中主内存属于共享数据区域,从某个程度上讲应该包括了堆和方法区,而工作内存数据线程私有数据区域,从某个程度上讲则应该包括程序计数器、虚拟机栈以及本地方法栈。

1、主内存
    主要存储的是Java实例对象,所有线程创建的实例对象都存放在主内存中,不管该实例对象是成员变量还是方法中的本地变量(也称局部变量),当然也包括了共享的类信息、常量、静态变量。由于是共享数据区域,多条线程对同一个变量进行访问可能会发现线程安全问题。
2、工作内存
    主要存储当前方法的所有本地变量信息(工作内存中存储着主内存中的变量副本拷贝),每个线程只能访问自己的工作内存,即线程中的本地变量对其它线程是不可见的,就算是两个线程执行的是同一段代码,它们也会各自在自己的工作内存中创建属于当前线程的本地变量,当然也包括了字节码行号指示器、相关Native方法的信息。注意由于工作内存是每个线程的私有数据,线程间无法相互访问工作内存,因此存储在工作内存的数据不存在线程安全问题。
















参考:https://blog.csdn.net/javazejian/article/details/72772461

         《深入理解java虚拟机》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值