<深入Java虚拟机>之1.1:内存类型

   众所周知C,C++系开发工程师在内存管理方面,既是"至高无上"的总裁,又是每天"996"的基层员工---他们拥有对象的所有权利,但是又要慢慢辛苦地维护对象的生命周期。是对"一般"的C,C++程序员的一项艰巨挑战。

   但是Java程序员不需要再为每一个对象去担心何时new/delete对象,也不容易出现内存泄漏问题(不需要编写复制构造函数,析构函数,重载=表达式)。由于jvm虚拟机的存在一切显得非常美好。But,也正是这种"至高无上"的权利交给jvm,一旦程序出现莫名的泄露,oom问题的时候会一下子无所适从。Java强的地方不是语言部分而是JVM生态。现在由于cpu发展从高频率编程多核心,并行计算非常重要,Java外围的Apache的Hadoop Map Reduce等大数据技术以及Google的Dalvik,Art虚拟机都是基于JVM生态技术,所以我们需要深入学习Java虚拟机的内在!

   在讨论JVM内存区域划分之前,先来看一下Java程序具体执行的过程:

Java程序执行的过程

pic来源于cnblogs

   首先java源程序会被javac编译成字节码(.class结尾),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。在运行过程中JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。我们生成的对象一般由他统一自动管理。

Runtime Data Area (我们关注的重点)

   下面我们来了解一下运行时数据区的每部分具体用来存储程序执行过程中的哪些数据。

Runtime Data Area

来源于Internet

   运行时数据区通常包括这几个部分:程序计数器(Program Counter Register)、Java栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。

   ️1⃣️.程序计数器类似于CPU里的PC寄存器的概念(保存下一条指令的所在存储单元的地址),表示当前thread执行的字节码的行号的标示。由于在JVM中multithreading是通过thread轮流切换来获得CPU 时间片的,因此,在任一具体时刻,一个CPU的内核只会执行一条thread中的指令,因此,为了能够使得每个thread都在thread切换后能够恢复在切换之前的程序执行位置,每个thread都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。因此,这类内存区域为"thread私有"内存。

   ️2⃣️.Java虚拟机栈(Java Vitual Machine Stack), 跟C/C++的数据段中的栈类似。

   每个thread执行一个方法时候会创建一个栈帧,栈帧存放了局部变量表,操作数的栈,运行时常量的引用。局部变量表存放了:基本数据类型,对象引用和方法返回地址。当thread执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。因此可知,thread当前执行的方法所对应的栈帧必定位于Java栈的顶部。讲到这里,大家就应该会明白为什么 在 使用 递归方法的时候容易导致栈内存溢出的现象了。一般会抛出OutOfMemoryError。每个thread都会有一个自己的Java栈,互不干扰。

   ️3⃣️. Java堆(Java Heap)

   这里是JVM管理内存中最大的一块,所有thread都共享这块内存,几乎所有的对象(实例)都在这里创建,被分配内存空间。所以这里也是垃圾收集者管理的主要区域,也叫GC堆(Garbage Collected Heap),内存大小不是固定不变,可以不需要连续存储。具体结构后面会详细说明。

   ️4⃣️. Java方法区(Method Area / Class Area)

和Heap区一样,这里是所有thread共享的,主要用于存储已被类加载器加载的类信息,常量,static变量,JIT编译后的代码等。一般把这个区域也叫做Permanent Generation(永久代)。和Heap一样,内存大小不是固定不变,可以不需要连续存储,还可以不参与垃圾回收。

在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。

/**

* 运行是常量池溢出

* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M

*/public class RuntimeConstantPoolOOM {

    public static void main(String[] args) {       

        List <string> list =new ArrayList();

        int i =0;

        while(true) {            

            list.add(String.valueOf(i++));      

      } 

   }

}

//结果JavaHotSpot(TM)64-Bit Server VM warning: ignoring option PermSize=10M; support was removedin8.0JavaHotSpot(TM)64-Bit Server VM warning: ignoring option MaxPermSize=10M; support was removedin8.0// 分析我使用的时jdk8.0发生如上错误,这个说明永久代已经在java8.0中被移除,被元空间替代。关于为啥要移除替代本篇不累赘。如果使用的jdk8.0一下版本则会出现OOM:PermGen space这样可以证明常量池属于方法区//VM Args:-XX:MaxMetaspaceSize=2M(这样设置元空间大小 )

5⃣️   ️.  本地方法栈

   在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。

  直接内存(Direct Memory)

   直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,它直接从操作系统中分配,因此不受Java堆大小的限制,但是会受到本机总内存的大小及处理器寻址空间的限制,因此它也可能导致OutOfMemoryError异常出现。在JDK1.4中新引入了NIO机制,它是一种基于通道与缓冲区的新I/O方式,可以直接从操作系统中分配直接内存,即在堆外分配内存,这样能在一些场景中提高性能,因为避免了在Java堆和Native堆中来回复制数据。关于NIO的详细使用可以参考Java NIO


  对象实例化分析

  对内存分配情况分析最常见的示例便是对象实例化:

  String s = new String("Hello");

这段代码的执行会涉及java栈、Java堆、方法区三个最重要的内存区域。假设该语句出现在方法体中,及时对JVM虚拟机不了解的Java使用这,应该也知道obj会作为引用类型(reference)的数据保存在Java栈的本地变量表中,而会在Java堆中保存该引用的实例化对象,但可能并不知道,Java堆中还必须包含能查找到此对象类型数据的地址信息(如对象类型、父类、实现的接口、方法等),这些类型数据则保存在方法区中。


参考资料:

  www.google.com

《深入理解Java虚拟机》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容