JAVA虚拟机在执行JAVA程序的时候,会把它管理的内存分成若干不同的数据区域,每个区域都有各自的用途。目前大致把JVM内存模型划分为五个区域:程序计数器,虚拟机栈,本地方法栈,堆和方法区。

程序计数器

程序计数器(ProgramCounterRegister)是当前线程所执行的字节码的行号指示器。这句话理解起来有点拗口,打个比方,我看书看到一半的时候突然接到领导电话”XX啊,线上那个项目出BUG了,赶紧来公司加个班解决!“,这时书没看完啊怎么办?我会在当前页夹个书签,以便下次再看的时候接着上次看的地方往下读。而程序计数器就是这样一个作用。我们的CPU多线程处理能力有限,常规的CPU也就是4核8线程,表示同一时间段最多能同时处理8个线程。而我们的程序往往是几百上千个线程在跑。所以不得不采用线程之间来回切换的形式来执行程序。程序计数器就是线程的”书签“,用来记录当前线程执行到方法的哪一步,以便下次线程切回来的时候从上次执行的内存地址继续执行。程序计数器是线程私有的,各个线程之间的计数器互不影响,独立存储。程序计数器也是唯一在Java 虚拟机规范中没有规定任何OutOfMemoryError 的区域。

ps:JVM还有个东西叫方法计数器,是用来记录方法执行次数的,用于JIT。当方法执行次数达到阈值的时候,JVM会判定该方法为热点方法,从而将该方法编译为机器码,从而提高执行效率,两者概念别搞混淆了。

虚拟机栈

虚拟机栈(Java Virtual Machine Stacks)与程序计数器一样,也是线程私有的,它的生命周期与线程相同。我们JAVA程序中的所有线程都被它管理。线程是什么?网上这种概念一找一大堆,我的理解很简单,线程就是方法的执行者,java程序中所有方法只能被线程执行。一个用户请求过来就创建了一个线程,一直到请求回应这个线程生命也走到了尽头。该请求在我们的服务端执行了哪些操作都是在这个线程中实现的,线程每执行一个方法就会创建一个栈帧,栈帧用来存储当前方法的局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从被调用至返回的过程, 就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

在Java 虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度(如循环嵌套/死循环),将抛出StackOverflowError 异常;如果虚拟机栈无法申请到足够的内存时会抛出OutOfMemoryError 异常。ps:普通线程大概消耗1M左右的内存,如果项目中线程数过多也会导致在该区域内存溢出,抛出OutOfMemoryError 异常。所以项目中能用线程池就用线程池限制和维护线程数量。

本地方法栈

本地方法栈(Native Method Stacks)与虚拟机栈非常类似,只不过虚拟机栈为虚拟机执行Java 方法服务,而本地方法栈则是为虚拟机使用到的native 方法服务。我们看JDK源码的时候经常看到有的方法前面有native修饰,这些都是本地方法,由非JAVA语言实现。

示例如下

package java.lang;
public class Object{
private static native void registerNatives();
...
...
public final native Class<?> getClass();
public native int hashCode();
protected native Object clone() throws CloneNotSupportedException;
public final native void notify();
...
}

与 虚拟机栈类似,本地方法栈也会抛出StackOverflowError和OutOfMemoryError 异常。以前项目中遇到过这种场景,遍历获取服务器某个目录下面所有文件夹和文件的时候抛出OutOfMemoryError 异常,提示是native方法报错。这时候别被native误导,native方法轻易不抛异常,就算抛异常也是我们打开方式有误,结合场景推测应该是有大文件在该目录下从而导致内存溢出,然后果然找到了大文件。

Java 堆

JAVA堆(Heap)是JVM内存管理中区域最大一块,也是GC垃圾回收器最活跃的区域,我们所有对象的生命周期都在堆里面。由于堆里面所有数据都是对虚拟机栈中所有线程共享,所以会造成并发编程的时候线程不安全的问题,这个我们先不讨论。现代GC主要采用的是分代回收的策略,将我们的堆主要划分为新生代(Eden区、From Survivor区和To Survivor区)和老年代。新生代就像炼狱,里面的对象朝生暮死,每分每秒都在煎熬,熬不下去就game over被扔到GC的销毁队列挨个销毁,熬下去了就跑到老年代去颐享天年。JVM默认配置一个对象如果经历了15次GC回收都还存活的话,就转移到老年代,特殊的大对象(如数组)除外。根据Java 虚拟机规范的规定,当JAVA堆无法满足内存分配需求时,将会抛出OutOfMemoryError 异常。ps:老年代不会轻易GC,但是老年代空间有限的情况下如果空间满了,则会促使GC来次大扫除--FULL GC,FULL GC是非常影响性能的,因为在执行FULL GC的时候,其他所有线程都不得不停下来等待,也就是所谓的STOP THE WORLD,一个好的JVM配置,基本不会出现 FULL GC的情况。

方法区

方法区(Method Area)存放虚拟机加载的类信息,静态变量,常量等数据。根据Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常。同堆一样,方法区也是对所有线程共享的。 JDK1.8之前,大家习惯于把方法区称之为”永久代“,这是因为HotSpot 虚拟机的设计团队选择把GC 分代收集扩展到了方法区,但是为了跟堆区分出来又取了一个别名叫非堆。1.8以后用”元空间“取代了永久代的概念,元空间不再是jvm内存的一部分,而是直接在于本机内存中。而将常量池移到堆中。

希望这篇文章能给大家一些提示。

浅谈JVM内存模型的更多相关文章

  1. 老李谈JVM内存模型

    老李谈JVM内存模型   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478,咨 ...

  2. 浅谈Java内存模型

    Java内存模型虽说是一个老生常谈的问题 ,也是大厂面试中绕不过的,甚至初级面试也会问到.但是真正要理解起来,还是相当困难,主要这个东西看不见,摸不着.网上已经有大量的博客,但是人家的终究是人家的,自 ...

  3. 浅谈JVM - 内存结构(二)- 虚拟机栈|凡酷

    2.1 定义 Java Virtual Machine Stacks(Java虚拟机栈) Java 虚拟机栈描述的是 Java 方法执行的内存模型,用于存储栈帧,是线程私有的,生命周期随着线程启动而产 ...

  4. 浅谈JVM内存分配与垃圾回收

    大家好,我是微尘,最近又去翻了周志明老师的<深入理解Java虚拟机>这本书.已经看了很多遍了,每次都感觉似乎看懂了,但没过多久就忘了.这次翻了第三章的垃圾收集器与内存分配策略,感觉有了新的 ...

  5. 浅谈JVM内存区域划分

    好吧,虽说真的有看过<深入分析Java Web技术内幕>一书,但当时看的时候还是一知半解,稀里糊涂的看完了.本来是打算暑假拿起来再看一遍的,但是早两天一个阿里学长给我做了个小面试,让我颇受 ...

  6. 浅谈jvm中的垃圾回收策略

    下面小编就为大家带来一篇浅谈jvm中的垃圾回收策略.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧   java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已 ...

  7. JVM内存模型与GC算法(简介)

    JVM内存模型如上图,需要声明一点,这是<Java虚拟机规范(Java SE 7版)>规定的内容,实际区域由各JVM自己实现,所以可能略有不同.以下对各区域进行简短说明. 1.1程序计数器 ...

  8. JVM内存模型和结构详解(五大模型图解)

    JVM内存模型和Java内存模型都是面试的热点问题,名字看感觉都差不多,实际上他们之间差别还是挺大的. 通俗点说,JVM内存结构是与JVM的内部存储结构相关,而Java内存模型是与多线程编程相关@mi ...

  9. JVM内存模型、指令重排、内存屏障概念解析

    在高并发模型中,无是面对物理机SMP系统模型,还是面对像JVM的虚拟机多线程并发内存模型,指令重排(编译器.运行时)和内存屏障都是非常重要的概念,因此,搞清楚这些概念和原理很重要.否则,你很难搞清楚哪 ...

随机推荐

  1. 梦想CAD控件安卓文字样式

    增加文字样式 用户可以增加文字样式到数据库,并设置其字体等属性,具体实现代码如下: // 增加文字样式 //getCurrentDatabase()返回当前数据库对象 //getTextstyle() ...

  2. string 字符串--------redis

    APPEND 语法:APPEND KEY VALUE 如果key已经存在并且是一个字符串,append 命令将value追加到key原来的值的末尾. 如果key不存在,append就简单地将给定key ...

  3. 类模板成员函数默认值问题:an out-of-line definition of a member of a class template cannot have default arguments

    template <typename T> class A { ); }; template<typename T> ) { /* */ } 对于类似上文代码,VS编译器会报 ...

  4. type、object、class之间的关系

    class Foo: pass print(type(int)) # <class 'type'> print(type(str)) # <class 'type'> prin ...

  5. Linux:SAMBA共享、NFS共享、Autofs自动挂载

    SAMBA.NFS共享区别 NFS开源文件共享程序:NFS(NetworkFile System)是一个能够将多台Linux的远程主机数据挂载到本地目录的服务,属于轻量级的文件共享服务,不支持Linu ...

  6. buf.readInt8()

    buf.readInt8(offset[, noAssert]) offset {Number} 0 noAssert {Boolean} 默认:false 返回:{Number} 从该 Buffer ...

  7. 微信小程序火爆,谁能在微信小程序赚取第一桶金?

    2016年末,最火的话题:微信小程序.身边好多朋友蠢蠢欲动的想要借微信小程序创业,春节期间整理思绪,我们就简单说说微信的小程序可能会让哪些人赚钱: 1,微信小程序培训,能够快速赚钱 做培训的肯定首先赚 ...

  8. vuex----------state的基础用法

    先使用vue cli构建一个自己的vue项目 1.npm i -g vue-cli 2.vue init webpack sell (sell是你的项目名) 3.一路回车(在这个过程中会提示你是否安装 ...

  9. codeforces 689 Mike and Shortcuts(最短路)

    codeforces 689 Mike and Shortcuts(最短路) 原题 任意两点的距离是序号差,那么相邻点之间建边即可,同时加上题目提供的边 跑一遍dijkstra可得1点到每个点的最短路 ...

  10. PAT 1129 Recommendation System

    Recommendation system predicts the preference that a user would give to an item. Now you are asked t ...