Java内存数据模型

本篇文章带来的是对Java内存数据模型的介绍,这对于我们深入理解Jvm虚拟机工作的原理和Java内存的划分大有裨益,好了,为了让我们理解的更为深刻,我们将会加入图片辅助的方法去理解。

本篇博文的目录:

一:Java内存数据模型的介绍

二:线程私有内存

三:程序计数器

四:Java虚拟机栈

五:本地方法栈

六:Java堆

七:方法区

八:运行时常量池

九:总结

一:java内存数据模型的介绍

java程序在运行的时候会在内存中开辟不同的空间用以管理不用的内存区域,每个区域都有自己的功能,创建和销毁时间,有的区域会随着虚拟机的启动而创建,而有的区域会随着用户线程的创建而销毁。按照空间,分为如下不同的空间,接下来我们将按照不同的区域进行学习,学习它不同区域的功能和用法

图 1-1 :java内存数据模型

二:线程私有内存

      我们先来看一下多线程运行原理:其实cpu在运行的时候每次在同一特定的时间点只能运行一个线程(单核的情况下),只不过它切换的速度非常之快,让我们觉的它是在进行多线程运行,本质上它还是单一运行的。所以这就会必然引出一个问题:cpu切换线程如何保证它自身的运行不受其他的线程影响,保证每个线程都是独立不受外部侵扰的,这就产生了线程私有内存这个概念,主要是维持线程的安全、稳定、高效的运转。关于这一点也很好理解,比如我们去一个快速餐厅吃饭,我们点好了菜,会产生菜单小票,这个小票上面有编号,就是每个线程的“私有内存”,服务员再进行不同顾客上菜的时候就有了区分度,这样就可以顺利找到不同的顾客(切换不同的线程);在java线程中,程序计数器、虚拟机栈、本地方法栈都属于线程私有的。

注意点:线程私有不存在多线程并发的资源竞争问题,因为其享有的内存是互不影响的,不存在并发问题

与线程私有相对,就有线程公有内存,这个区域在jvm虚拟机中有个特定的称呼叫做:主内存

三:程序计数器:

   对应于图上标记的深红色部分,主要是指程序在运行过程中所执行的字节码(.class)文件的行号指示,也称作行号指示器,程序流程的分支、循环、异常处理等基础功能都需要它的引导来完成。它占有的内存空间比较小,它的运行的原理是:通过改变计数器的值来选取下一条的需要执行的字节码命令,而这个值具体指的是虚拟机在Java方法中字节码指令的地址,但是如果执行的是Native方法,那么它的计数器的值是为空的。

注意

1:它是java中唯一一个没有内存溢出(out of memory)情况的区域。可以思考一下这点是为什么?它是进行线程运行的指示灯,如果没有了它,程序也就无法运行了。

2:它属于线程私有的:每个线程内部都有一个程序计数器,为了保证每个线程切换前后都能正常运行。

四:Java虚拟机栈:

      虚拟机栈主要是作用在java方法运行时候,每个线程在运行到一个方法的入口都会创建一个栈帧,创建栈帧的目的在于存储局部变量、操作数栈、动态链接、方法出口等信息。按照这个原理,那么一个方法在从调用直到完全执行完毕,都会对应一个从入栈到出栈的过程。

这里我们说明一下局部变量,它的含义就是定义在java方法内部中的变量,对应于java中8大基本数据类型,byte、int、float、boolean、char、short、long、reference:(long和double占用2个空间,其余1个)局部变量表里我们需要注意的是,它在编译期已经完全了内存分配,这样栈帧在用局部变量的时候,它占用的内存是已经确认的,不需要再分配,这就一定程度上减少了栈帧的工作量。

注意:

1:当线程请求的栈帧的深度大于虚拟机允许的深度,就会抛出stackOverFlow异常

2:我们平时所说的堆栈,其中的栈就是指的是这里的栈帧

3:它也是线程私有的,并且和线程的生命周期相同。

图 2-1:虚拟机栈

五:本地方法栈:

        本地方法栈,顾名思义它代表的就是本地方法Native执行的栈帧,在jdk的源码中我们可以看到很多命名为Native的方法,Native方法很大一部分是采用C/C++写的,但是它对Native采用的数据结构、语言等都没有做具体的要求,这一点完全是由java虚拟机进行实现的。

注意:

1:这个区域会抛出oom或者sof(stackoverflowError)异常

2:同样它属于本地线程私有的

 六:Java堆:

Java堆主要是存储对象的地方,同时它也是java内存管理区域最大的一块。当我们在程序中new一个对象出来或者新建一个数组,就会把对象存储这个区域。它是java的最重要的公共区域之一,与线程私有相对,它是属于线程公有的。基本上所有的对象都会存储在此区域,但也不是绝对的(随着JIT技术的成熟,这一点会发生微变)。堆是主要存放对象的地方,同时它就会产生另一个问题就是GC,当垃圾进行回收的时候,虚拟机并没有开辟新的空间,还在此区域进行,同时这个区域也叫“GC堆”,再细致划分下去,分为新生代、老年代,同时还分为Eden空间、From survivor空间、To Survior区域。为什么要划分的这么细致呢?其实还是主要还是为了更加有效率的回收,划分的区域越细致,那么垃圾回收器收集的时候只要去对应的地方直接回收就行,不用加上额外的判断逻辑。

注意点:

1:堆在逻辑上是连续不间断的内存空间,但是在物理上可以是不连续的内存空间

2:在堆中如果没有完成内存的实例分配就会抛出oom

3:java堆是线程公有的,所有的线程共享这一片区域

图 3-1 java堆内存

七:方法区

方法区主要是用来存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,比如我们在代码中定义的Constant常量就会在这个区域存储。在java虚拟机规范中,它是属于堆的逻辑部分。同时在这个区域中,它也会有垃圾回收器工作,这个区域叫做“永久代”,之所以叫做永久代,因为它比新生代和老年代拥有更长的生命周期,但是并不是在这个区域它就会万事大吉了,永久代依然会存在垃圾回收的情况,只不过相对来说较少

注意点

1:此区域属于线程公有的,线程的类信息、常量、静态变量、编译代码都在此区域进行存储

2:此区域会抛出oom异常,发生在方法区无法进行内存分配时

图:4-1 方法区

八:运行时常量池:

     运行时常量池主要是方法区的一部分,class文件除了有类的版本、字段、方法接口等描述信息外,还有一项信息是常量池,用于存储编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区运行时常量池中存放。

注意:此区域同样会发生oom异常

九:总结

本篇博文主要是对java的内存数据模型区域划分进行了简单的介绍,没有深入细致过多的介绍。不过我们在整体上有一个感性的认识,理解java内存区域的划分,以及这样的划分的好处,还有设计到线程的部分,理解并发的问题。这部分属于虚拟机底层的东西,属于进阶。相信看完这篇文章后,我希望能回答以下几个问题。同时这些东西也是考究我们对于底层的认识,面试中也是经常会被提及到的东西

1:java内存模型分为哪几个区域?

2:请说出属于线程私有部分和线程公有部分的区域?

3:我们都知道内存是在按照“代”进行划分的,那么请问java堆中内存分为哪几代?分别位于什么区域?

4:为什么要把java内存划分这么多,划分这么多不嫌麻烦吗?有什么好处

我希望能思考以上问题,学习的时候就要进行多思考,深入思考这是为什么?这篇博文的介绍就到此结束了,下一篇见,对于java内存模型的理解有助于我们处理并发的问题,这是属于javaEE中高端进阶必不可少的基础,在此留个记录,同时分享出来,让大家也能清楚的认识Java内存模型同时提醒自己深入理解。

主要参考资料:

《深入Jvm虚拟机》

时间: 2024-09-29 05:21:18

Java内存数据模型的相关文章

(转)Java 内存整理——堆、栈、常量池

Java 内存分配: 1. 寄存器我们在程序中无法控制 2. 栈存放基本类型的变量数据,局部变量,和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中.) 3. 堆存放用new产生的对象,数组. 为了给垃圾回收器使用,堆主要分成三个区域,分别叫作New Generation,Old Generation或叫Tenured Generation,以及Perm space.New Generation是用来存放新建的对象的空间,在对象新建

Java 内存区域和GC机制

目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代 码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制.概括地说,该机制对 JVM(Java Virtual M

深入理解Java内存模型(四)——volatile

volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步.下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { //使用volatile声明64位的long型变量 volatile long vl = 0L; public void set(long l) { vl = l;

深入理解Java内存模型(1 ) -- 基础(转载)

原文地址:http://www.infoq.com/cn/articles/java-memory-model-1 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递. 在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信.在消息传递的并发模型里,线程之间没有公共状态,线

Java内存区域划分和GC机制

Java 内存区域和GC机制 目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代 码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制.概括地说,该机制对 JVM

JAVA 虚拟机深入研究(三)——Java内存区域

JAVA 虚拟机深入研究(一)--关于Java的一些历史 JAVA 虚拟机深入研究(二)--JVM虚拟机发展以及一些Java的新东西 JAVA 虚拟机深入研究(三)--Java内存区域 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的围城,城外的人想进去,城里的人想出来. Java运行的时候会把内存分为若干个,他们各有各的用途,每块区域的创建和销毁都是相对独立的,有的跟虚拟机一起混,有的则抱着用户的大腿同生共死. 按照第七版的<Java虚拟机规范>规定,JVM所管理的内存包括以下

对java内存模型的认识

浅谈java内存模型        不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的.其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改.总结java的内存模型,要解决两个主要的问题:可见性和有序性.我们都知道计算机有高速缓存的存在,处理器并不是每次处理数据都是取内存的.JVM定义了自己的内存模型,屏蔽了底层平台内存管理细节,对于java开发人员,要清楚在jvm内存模型的基础上,如果解决多线程的可见性和有序性

Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结

最近老是遇见服务器内存溢出的问题,故在网上搜了搜,总结了一些java内存溢出的解决方式 java.lang.OutOfMemoryError这个错误我相信大部分开发人员都有遇到过,产生该错误的原因大都出于以下原因:JVM内存过小.程序不严密,产生了过多的垃圾. 导致OutOfMemoryError异常的常见原因有以下几种: 内存中加载的数据量过于庞大,如一次从数据库取出过多数据: 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收: 代码中存在死循环或循环产生过多重复的对象实体: 使用的

Java内存结构和数据类型

Java内存结构 内存就是暂时对数据的一个存储,他的存储速度非常的快,但是他是暂时的存储,从开机时开始存储,掉电或关机之后数据全部丢失.内存的生命周期就是开机和关机,开机的时候开始计算,关机什么都没有了.优点存储速度快,缺点容易坏掉,如果开机的时候,一点反映都没有,屏幕不亮键盘鼠标不亮,这种情况下一般都是内存条有问题.机器蓝屏,指令错误都是内存引起的. 程序的数据都是存储在内存里面,不存储在硬盘上因为硬盘不安全,可以读取数据.但是内存就不一样,内存他不允许去读取内存数据,并且速度很快所以我们的程